/* * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "applib/graphics/gtypes.h" #include "applib/graphics/graphics.h" #include "util/attributes.h" #include "clar.h" #include "util.h" // Helper Functions //////////////////////////////////// #include "test_graphics.h" #include "${BIT_DEPTH_NAME}/test_framebuffer.h" // Stubs //////////////////////////////////// #include "graphics_common_stubs.h" #include "stubs_applib_resource.h" // Definitions #define SW_EVEN 4 #define SW_ODD 5 // Includes all possible fields for all shapes // The fields that are not needed for a particular shape will be zeroed out. typedef struct PACKED { char func[30]; GContext ctx; GPoint p0; GPoint p1; GRect r0; uint16_t radius; uint8_t quadrant; GCornerMask corner_mask; int16_t major_axis_offset; Fixed_S16_3 offset_start; Fixed_S16_3 offset_stop; bool anti_aliased; uint16_t brightness; GColor color; GBitmap fb; } ArgsForMock; static ArgsForMock s_last_args_for_mock; static GContext context; static FrameBuffer *fb = NULL; ///////////////////////////////////// /// FUNCTION OVERRIDES ///////////////////////////////////// void graphics_line_draw_1px_non_aa(GContext* ctx, GPoint p0, GPoint p1) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .p0 = p0, .p1 = p1 }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void graphics_line_draw_1px_aa(GContext* ctx, GPoint p0, GPoint p1) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .p0 = p0, .p1 = p1 }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void graphics_line_draw_stroked_aa(GContext* ctx, GPoint p0, GPoint p1, uint8_t stroke_width) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .p0 = p0, .p1 = p1 }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void graphics_line_draw_stroked_non_aa(GContext* ctx, GPoint p0, GPoint p1, uint8_t stroke_width) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .p0 = p0, .p1 = p1 }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void prv_fill_rect_non_aa(GContext* ctx, const GRect *rect, uint16_t radius, GCornerMask corner_mask, GColor fill_color) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .r0 = *rect, .radius = radius, .corner_mask = corner_mask }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void prv_fill_rect_aa(GContext* ctx, const GRect *rect, uint16_t radius, GCornerMask corner_mask, GColor fill_color) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .r0 = *rect, .radius = radius, .corner_mask = corner_mask }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void prv_draw_rect(GContext *ctx, const GRect *rect) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .r0 = *rect, .radius = 0, .corner_mask = GCornerNone }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void prv_draw_rect_aa_stroked(GContext *ctx, const GRect *rect, uint8_t stroke_width) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .r0 = *rect, .radius = 0, .corner_mask = GCornerNone }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void prv_draw_rect_stroked(GContext *ctx, const GRect *rect, uint8_t stroke_width) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .r0 = *rect, .radius = 0, .corner_mask = GCornerNone }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void graphics_circle_draw_1px_non_aa(GContext* ctx, GPoint p, uint16_t radius) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .p0 = p, .radius = radius }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void graphics_circle_draw_1px_aa(GContext* ctx, GPoint p, uint16_t radius) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .p0 = p, .radius = radius }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void graphics_circle_draw_stroked_aa(GContext* ctx, GPoint p, uint16_t radius, uint8_t stroke_width) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .p0 = p, .radius = radius }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void graphics_circle_draw_stroked_non_aa(GContext* ctx, GPoint p, uint16_t radius, uint8_t stroke_width) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .p0 = p, .radius = radius }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void graphics_internal_circle_quadrant_fill_aa(GContext* ctx, GPoint p, uint16_t radius, GCornerMask quadrant) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .p0 = p, .radius = radius, .corner_mask = quadrant }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void graphics_circle_fill_non_aa(GContext* ctx, GPoint p, uint16_t radius) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .p0 = p, .radius = radius }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void prv_draw_round_rect(GContext* ctx, const GRect *rect, uint16_t radius) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .r0 = *rect, .radius = radius, .corner_mask = GCornersAll }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void prv_draw_round_rect_aa(GContext* ctx, const GRect *rect, uint16_t radius) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .r0 = *rect, .radius = radius, .corner_mask = GCornersAll }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void prv_draw_round_rect_aa_stroked(GContext* ctx, const GRect *rect, uint16_t radius, uint8_t stroke_width) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .r0 = *rect, .radius = radius, .corner_mask = GCornersAll }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } void prv_draw_round_rect_stroked(GContext* ctx, const GRect *rect, uint16_t radius, uint8_t stroke_width) { s_last_args_for_mock = (ArgsForMock){ .ctx = *ctx, .r0 = *rect, .radius = radius, .corner_mask = GCornersAll }; strncpy(s_last_args_for_mock.func, __func__, sizeof(s_last_args_for_mock.func)); } ///////////////////////////////////// /// HELPER FUNCTIONS ///////////////////////////////////// // Copy over the last arguments - take the largest possible shape static void copy_last_args_for_mock(ArgsForMock *actual_args, ArgsForMock *last_args) { memcpy(actual_args, last_args, sizeof(ArgsForMock)); } // Zero out the arguments from the last run static void reset_last_args_for_mock() { memset(&s_last_args_for_mock, 0x00, sizeof(s_last_args_for_mock)); } // Validate the arguments based on the shape that is drawn static bool validate_args(ArgsForMock *actual_args, ArgsForMock *valid_args) { if (memcmp(actual_args, valid_args, sizeof(ArgsForMock)) == 0) { return true; } return false; } // This macro will call the expected code_block and then validate the arguments set in code_block // match what was expected from the last mock call (i.e. if graphics_draw_line was called, then // internally it would call prv_draw_line... and the actual_args would be set to the arguments // that are set in prv_draw_line... so when compared to directly calling prv_draw_line..., the two // should match. #define ASSERT_CALLED(code_block) \ do {\ ArgsForMock actual_args; \ copy_last_args_for_mock(&actual_args, &s_last_args_for_mock); \ reset_last_args_for_mock(); \ code_block; \ bool cmp_result = validate_args(&actual_args, &s_last_args_for_mock); \ printf("1 %d %d %d %d\n", actual_args.r0.origin.x, actual_args.r0.origin.y, \ actual_args.r0.size.w, actual_args.r0.size.h); \ actual_args = s_last_args_for_mock; \ printf("2 %d %d %d %d\n", actual_args.r0.origin.x, actual_args.r0.origin.y, \ actual_args.r0.size.w, actual_args.r0.size.h); \ cl_assert(cmp_result); \ } while(0) // This is used to make sure nothing has changed when calling code_block // i.e. no prv_... functions have been called // If any prv_... functions are called then s_last_args_for_mock will be updated #define ASSERT_NO_CHANGE(code_block) \ do {\ ArgsForMock actual_args; \ reset_last_args_for_mock(); \ copy_last_args_for_mock(&actual_args, &s_last_args_for_mock); \ code_block; \ bool cmp_result = validate_args(&actual_args, &s_last_args_for_mock); \ cl_assert(cmp_result); \ } while(0) static void setup_test(GContext* ctx, bool antialiased, uint8_t stroke_width, GColor stroke_color, GColor fill_color, bool lock) { graphics_context_set_antialiased(ctx, antialiased); graphics_context_set_stroke_width(ctx, stroke_width); graphics_context_set_stroke_color(ctx, stroke_color); graphics_context_set_fill_color(ctx, fill_color); ctx->lock = lock; reset_last_args_for_mock(); } // Setup void test_graphics_context_${BIT_DEPTH_NAME}__initialize(void) { fb = malloc(sizeof(FrameBuffer)); framebuffer_init(fb, &(GSize) {DISP_COLS, DISP_ROWS}); test_graphics_context_init(&context, fb); } // Teardown void test_graphics_context_${BIT_DEPTH_NAME}__cleanup(void) { free(fb); } ///////////////////////////////////// /// TESTS ///////////////////////////////////// void test_graphics_context_${BIT_DEPTH_NAME}__set(void) { GDrawState draw_state; GColor color; // Stroke Color graphics_context_set_stroke_color(&context, GColorClear); cl_assert_equal_i(context.draw_state.stroke_color.argb, GColorClear.argb); color = GColorBlue; graphics_context_set_stroke_color(&context, color); #if PBL_COLOR cl_assert_equal_i(context.draw_state.stroke_color.argb, GColorBlue.argb); #else cl_assert_equal_i(context.draw_state.stroke_color.argb, GColorBlack.argb); #endif color.a = 2; graphics_context_set_stroke_color(&context, color); #if PBL_COLOR cl_assert_equal_i(context.draw_state.stroke_color.argb, GColorBlue.argb); #else cl_assert_equal_i(context.draw_state.stroke_color.argb, GColorBlack.argb); #endif color.a = 1; graphics_context_set_stroke_color(&context, color); cl_assert_equal_i(context.draw_state.stroke_color.argb, GColorClear.argb); color.a = 0; graphics_context_set_stroke_color(&context, color); cl_assert_equal_i(context.draw_state.stroke_color.argb, GColorClear.argb); // Stroke Color - 2-bit graphics_context_set_stroke_color_2bit(&context, GColor2Black); cl_assert(gcolor_equal(context.draw_state.stroke_color, GColorBlack)); // Fill Color graphics_context_set_fill_color(&context, GColorClear); cl_assert_equal_i(context.draw_state.fill_color.argb, GColorClear.argb); color = GColorOrange; graphics_context_set_fill_color(&context, color); #if PBL_COLOR cl_assert_equal_i(context.draw_state.fill_color.argb, GColorOrange.argb); #else cl_assert_equal_i(context.draw_state.fill_color.argb, GColorDarkGray.argb); #endif color.a = 2; graphics_context_set_fill_color(&context, color); #if PBL_COLOR cl_assert_equal_i(context.draw_state.fill_color.argb, GColorOrange.argb); #else cl_assert_equal_i(context.draw_state.fill_color.argb, GColorDarkGray.argb); #endif color.a = 1; graphics_context_set_fill_color(&context, color); cl_assert_equal_i(context.draw_state.fill_color.argb, GColorClear.argb); color.a = 0; graphics_context_set_fill_color(&context, color); cl_assert_equal_i(context.draw_state.fill_color.argb, GColorClear.argb); // Fill Color - 2-bit graphics_context_set_fill_color_2bit(&context, GColor2White); cl_assert(gcolor_equal(context.draw_state.fill_color, GColorWhite)); // Compositing Mode graphics_context_set_compositing_mode(&context, GCompOpOr); cl_assert(context.draw_state.compositing_mode == GCompOpOr); // Text Color graphics_context_set_text_color(&context, GColorClear); cl_assert_equal_i(context.draw_state.text_color.argb, GColorClear.argb); color = GColorYellow; graphics_context_set_text_color(&context, color); #if PBL_COLOR cl_assert_equal_i(context.draw_state.text_color.argb, GColorYellow.argb); #else cl_assert_equal_i(context.draw_state.text_color.argb, GColorWhite.argb); #endif color.a = 2; graphics_context_set_text_color(&context, color); #if PBL_COLOR cl_assert_equal_i(context.draw_state.text_color.argb, GColorYellow.argb); #else cl_assert_equal_i(context.draw_state.text_color.argb, GColorWhite.argb); #endif color.a = 1; graphics_context_set_text_color(&context, color); cl_assert_equal_i(context.draw_state.text_color.argb, GColorClear.argb); color.a = 0; graphics_context_set_text_color(&context, color); cl_assert_equal_i(context.draw_state.text_color.argb, GColorClear.argb); // Text Color - 2-bit graphics_context_set_text_color_2bit(&context, GColor2White); cl_assert(gcolor_equal(context.draw_state.text_color, GColorWhite)); #if PBL_COLOR // Antialiased graphics_context_set_antialiased(&context, true); cl_assert(context.draw_state.antialiased == true); #endif // Stroke Width graphics_context_set_stroke_width(&context, 11); cl_assert(context.draw_state.stroke_width == 11); // Make sure setting to zero is ignored draw_state = graphics_context_get_drawing_state(&context); graphics_context_set_stroke_width(&context, 0); cl_assert(memcmp(&draw_state, &context.draw_state, sizeof(GDrawState)) == 0); // Check draw state memset(&draw_state, 0x5A, sizeof(GDrawState)); graphics_context_set_drawing_state(&context, draw_state); cl_assert(memcmp(&draw_state, &context.draw_state, sizeof(GDrawState)) == 0); } void test_graphics_context_${BIT_DEPTH_NAME}__draw_antialiased(void) { // Stroke width = 1, antialiased setup_test(&context, true, 1, GColorBlack, GColorBlack, false); graphics_draw_line(&context, GPoint(5, 5), GPoint(45, 10)); #if PBL_COLOR ASSERT_CALLED(graphics_line_draw_1px_aa(&context, GPoint(5, 5), GPoint(45, 10))); #else ASSERT_CALLED(graphics_line_draw_1px_non_aa(&context, GPoint(5, 5), GPoint(45, 10))); #endif setup_test(&context, true, 1, GColorBlack, GColorBlack, false); graphics_draw_rect(&context, &GRect(10, 20, 40, 10)); ASSERT_CALLED(prv_draw_rect(&context, &GRect(10, 20, 40, 10))); setup_test(&context, true, 1, GColorBlack, GColorBlack, false); graphics_draw_circle(&context, GPoint(50, 50), 10); #if PBL_COLOR ASSERT_CALLED(graphics_circle_draw_1px_aa(&context, GPoint(50, 50), 10)); #else ASSERT_CALLED(graphics_circle_draw_1px_non_aa(&context, GPoint(50, 50), 10)); #endif setup_test(&context, true, 1, GColorBlack, GColorBlack, false); graphics_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4); #if PBL_COLOR ASSERT_CALLED(prv_draw_round_rect_aa(&context, &GRect(20, 80, 40, 10), 4)); #else ASSERT_CALLED(prv_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4)); #endif } void test_graphics_context_${BIT_DEPTH_NAME}__draw_stroke_width_1(void) { // Stroke width 1, non-antialiased setup_test(&context, false, 1, GColorBlack, GColorBlack, false); graphics_draw_line(&context, GPoint(5, 5), GPoint(45, 10)); ASSERT_CALLED(graphics_line_draw_1px_non_aa(&context, GPoint(5, 5), GPoint(45, 10))); setup_test(&context, false, 1, GColorBlack, GColorBlack, false); graphics_draw_rect(&context, &GRect(10, 20, 40, 10)); ASSERT_CALLED(prv_draw_rect(&context, &GRect(10, 20, 40, 10))); setup_test(&context, false, 1, GColorBlack, GColorBlack, false); graphics_draw_circle(&context, GPoint(50, 50), 10); ASSERT_CALLED(graphics_circle_draw_1px_non_aa(&context, GPoint(50, 50), 10)); setup_test(&context, false, 1, GColorBlack, GColorBlack, false); graphics_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4); ASSERT_CALLED(prv_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4)); } void test_graphics_context_${BIT_DEPTH_NAME}__draw_stroke_width_2(void) { // Stroke width 2, non-antialiased setup_test(&context, false, 2, GColorBlack, GColorBlack, false); graphics_draw_line(&context, GPoint(5, 5), GPoint(45, 10)); ASSERT_CALLED(graphics_line_draw_stroked_non_aa(&context, GPoint(5, 5), GPoint(45, 10), 2)); setup_test(&context, false, 2, GColorBlack, GColorBlack, false); graphics_draw_rect(&context, &GRect(10, 20, 40, 10)); ASSERT_CALLED(prv_draw_rect(&context, &GRect(10, 20, 40, 10))); setup_test(&context, false, 2, GColorBlack, GColorBlack, false); graphics_draw_circle(&context, GPoint(50, 50), 10); ASSERT_CALLED(graphics_circle_draw_stroked_non_aa(&context, GPoint(50, 50), 10, 2)); setup_test(&context, false, 2, GColorBlack, GColorBlack, false); graphics_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4); ASSERT_CALLED(prv_draw_round_rect_stroked(&context, &GRect(20, 80, 40, 10), 4, 2)); } void test_graphics_context_${BIT_DEPTH_NAME}__draw_stroke_width_even(void) { // Stroke width even > 2, non-antialiased setup_test(&context, false, SW_EVEN, GColorBlack, GColorBlack, false); graphics_draw_line(&context, GPoint(5, 5), GPoint(45, 10)); ASSERT_CALLED(graphics_line_draw_stroked_non_aa(&context, GPoint(5, 5), GPoint(45, 10), SW_EVEN)); setup_test(&context, false, SW_EVEN, GColorBlack, GColorBlack, false); graphics_draw_rect(&context, &GRect(10, 20, 40, 10)); ASSERT_CALLED(prv_draw_rect_stroked(&context, &GRect(10, 20, 40, 10), SW_EVEN)); setup_test(&context, false, SW_EVEN, GColorBlack, GColorBlack, false); graphics_draw_circle(&context, GPoint(50, 50), 10); ASSERT_CALLED(graphics_circle_draw_stroked_non_aa(&context, GPoint(50, 50), 10, SW_EVEN)); setup_test(&context, false, SW_EVEN, GColorBlack, GColorBlack, false); graphics_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4); ASSERT_CALLED(prv_draw_round_rect_stroked(&context, &GRect(20, 80, 40, 10), 4, SW_EVEN)); } void test_graphics_context_${BIT_DEPTH_NAME}__draw_stroke_width_odd(void) { // Stroke width odd > 1, non-antialiased setup_test(&context, false, SW_ODD, GColorBlack, GColorBlack, false); graphics_draw_line(&context, GPoint(5, 5), GPoint(45, 10)); ASSERT_CALLED(graphics_line_draw_stroked_non_aa(&context, GPoint(5, 5), GPoint(45, 10), SW_ODD)); setup_test(&context, false, SW_ODD, GColorBlack, GColorBlack, false); graphics_draw_rect(&context, &GRect(10, 20, 40, 10)); ASSERT_CALLED(prv_draw_rect_stroked(&context, &GRect(10, 20, 40, 10), SW_ODD)); setup_test(&context, false, SW_ODD, GColorBlack, GColorBlack, false); graphics_draw_circle(&context, GPoint(50, 50), 10); ASSERT_CALLED(graphics_circle_draw_stroked_non_aa(&context, GPoint(50, 50), 10, SW_ODD)); setup_test(&context, false, SW_ODD, GColorBlack, GColorBlack, false); graphics_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4); ASSERT_CALLED(prv_draw_round_rect_stroked(&context, &GRect(20, 80, 40, 10), 4, SW_ODD)); } void test_graphics_context_${BIT_DEPTH_NAME}__draw_antialiased_stroke_width_2(void) { // Stroke width = 2, antialiased setup_test(&context, true, 2, GColorBlack, GColorBlack, false); graphics_draw_line(&context, GPoint(5, 5), GPoint(45, 10)); #if PBL_COLOR ASSERT_CALLED(graphics_line_draw_stroked_aa(&context, GPoint(5, 5), GPoint(45, 10), 2)); #else ASSERT_CALLED(graphics_line_draw_stroked_non_aa(&context, GPoint(5, 5), GPoint(45, 10), 2)); #endif setup_test(&context, true, 2, GColorBlack, GColorBlack, false); graphics_draw_rect(&context, &GRect(10, 20, 40, 10)); ASSERT_CALLED(prv_draw_rect(&context, &GRect(10, 20, 40, 10))); setup_test(&context, true, 2, GColorBlack, GColorBlack, false); graphics_draw_circle(&context, GPoint(50, 50), 10); #if PBL_COLOR ASSERT_CALLED(graphics_circle_draw_stroked_aa(&context, GPoint(50, 50), 10, 2)); #else ASSERT_CALLED(graphics_circle_draw_stroked_non_aa(&context, GPoint(50, 50), 10, 2)); #endif setup_test(&context, true, 2, GColorBlack, GColorBlack, false); graphics_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4); #if PBL_COLOR ASSERT_CALLED(prv_draw_round_rect_aa_stroked(&context, &GRect(20, 80, 40, 10), 4, 2)); #else ASSERT_CALLED(prv_draw_round_rect_stroked(&context, &GRect(20, 80, 40, 10), 4, 2)); #endif } void test_graphics_context_${BIT_DEPTH_NAME}__draw_antialiased_stroke_width_even(void) { // Stroke width even > 2, antialiased setup_test(&context, true, SW_EVEN, GColorBlack, GColorBlack, false); graphics_draw_line(&context, GPoint(5, 5), GPoint(45, 10)); #if PBL_COLOR ASSERT_CALLED(graphics_line_draw_stroked_aa(&context, GPoint(5, 5), GPoint(45, 10), SW_EVEN)); #else ASSERT_CALLED(graphics_line_draw_stroked_non_aa(&context, GPoint(5, 5), GPoint(45, 10), SW_EVEN)); #endif setup_test(&context, true, SW_EVEN, GColorBlack, GColorBlack, false); graphics_draw_rect(&context, &GRect(10, 20, 40, 10)); #if PBL_COLOR ASSERT_CALLED(prv_draw_rect_aa_stroked(&context, &GRect(10, 20, 40, 10), SW_EVEN)); #else ASSERT_CALLED(prv_draw_rect_stroked(&context, &GRect(10, 20, 40, 10), SW_EVEN)); #endif setup_test(&context, true, SW_EVEN, GColorBlack, GColorBlack, false); graphics_draw_circle(&context, GPoint(50, 50), 10); #if PBL_COLOR ASSERT_CALLED(graphics_circle_draw_stroked_aa(&context, GPoint(50, 50), 10, SW_EVEN)); #else ASSERT_CALLED(graphics_circle_draw_stroked_non_aa(&context, GPoint(50, 50), 10, SW_EVEN)); #endif setup_test(&context, true, SW_EVEN, GColorBlack, GColorBlack, false); graphics_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4); #if PBL_COLOR ASSERT_CALLED(prv_draw_round_rect_aa_stroked(&context, &GRect(20, 80, 40, 10), 4, SW_EVEN)); #else ASSERT_CALLED(prv_draw_round_rect_stroked(&context, &GRect(20, 80, 40, 10), 4, SW_EVEN)); #endif } void test_graphics_context_${BIT_DEPTH_NAME}__draw_antialiased_stroke_width_odd(void) { // Stroke width odd > 1, antialiased setup_test(&context, true, SW_ODD, GColorBlack, GColorBlack, false); graphics_draw_line(&context, GPoint(5, 5), GPoint(45, 10)); #if PBL_COLOR ASSERT_CALLED(graphics_line_draw_stroked_aa(&context, GPoint(5, 5), GPoint(45, 10), SW_ODD)); #else ASSERT_CALLED(graphics_line_draw_stroked_non_aa(&context, GPoint(5, 5), GPoint(45, 10), SW_ODD)); #endif setup_test(&context, true, SW_ODD, GColorBlack, GColorBlack, false); graphics_draw_rect(&context, &GRect(10, 20, 40, 10)); #if PBL_COLOR ASSERT_CALLED(prv_draw_rect_aa_stroked(&context, &GRect(10, 20, 40, 10), SW_ODD)); #else ASSERT_CALLED(prv_draw_rect_stroked(&context, &GRect(10, 20, 40, 10), SW_ODD)); #endif setup_test(&context, true, SW_ODD, GColorBlack, GColorBlack, false); graphics_draw_circle(&context, GPoint(50, 50), 10); #if PBL_COLOR ASSERT_CALLED(graphics_circle_draw_stroked_aa(&context, GPoint(50, 50), 10, SW_ODD)); #else ASSERT_CALLED(graphics_circle_draw_stroked_non_aa(&context, GPoint(50, 50), 10, SW_ODD)); #endif setup_test(&context, true, SW_ODD, GColorBlack, GColorBlack, false); graphics_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4); #if PBL_COLOR ASSERT_CALLED(prv_draw_round_rect_aa_stroked(&context, &GRect(20, 80, 40, 10), 4, SW_ODD)); #else ASSERT_CALLED(prv_draw_round_rect_stroked(&context, &GRect(20, 80, 40, 10), 4, SW_ODD)); #endif } void test_graphics_context_${BIT_DEPTH_NAME}__fill(void) { // Fill shape, non-antialiased (Stroke width/color N/A) setup_test(&context, false, 5, GColorBlack, GColorBlack, false); graphics_fill_rect(&context, &GRect(10, 20, 40, 10)); ASSERT_CALLED(prv_fill_rect_non_aa(&context, &GRect(10, 20, 40, 10), 0, GCornerNone, GColorBlack)); setup_test(&context, false, 5, GColorBlack, GColorBlack, false); graphics_fill_circle(&context, GPoint(50, 50), 10); ASSERT_CALLED(graphics_circle_fill_non_aa(&context, GPoint(50, 50), 10)); setup_test(&context, false, 5, GColorBlack, GColorBlack, false); graphics_fill_round_rect(&context, &GRect(20, 80, 40, 10), 4, GCornersAll); ASSERT_CALLED(prv_fill_rect_non_aa(&context, &GRect(20, 80, 40, 10), 4, GCornersAll, GColorBlack)); } void test_graphics_context_${BIT_DEPTH_NAME}__fill_antialiased(void) { // Fill shape, antialiased (Stroke width/color N/A) setup_test(&context, true, 5, GColorBlack, GColorBlack, false); graphics_fill_rect(&context, &GRect(10, 20, 40, 10)); #if SCREEN_COLOR_DEPTH_BITS == 1 ASSERT_CALLED(prv_fill_rect_non_aa(&context, &GRect(10, 20, 40, 10), 0, GCornerNone, GColorBlack)); #else ASSERT_CALLED(prv_fill_rect_aa(&context, &GRect(10, 20, 40, 10), 0, GCornerNone, GColorBlack)); #endif setup_test(&context, true, 5, GColorBlack, GColorBlack, false); graphics_fill_circle(&context, GPoint(50, 50), 10); #if PBL_COLOR ASSERT_CALLED(graphics_internal_circle_quadrant_fill_aa(&context, GPoint(50, 50), 10, GCornersAll)); #else ASSERT_CALLED(graphics_circle_fill_non_aa(&context, GPoint(50, 50), 10)); #endif setup_test(&context, true, 5, GColorBlack, GColorBlack, false); graphics_fill_round_rect(&context, &GRect(20, 80, 40, 10), 4, GCornersAll); #if SCREEN_COLOR_DEPTH_BITS == 1 ASSERT_CALLED(prv_fill_rect_non_aa(&context, &GRect(20, 80, 40, 10), 4, GCornersAll, GColorBlack)); #else ASSERT_CALLED(prv_fill_rect_aa(&context, &GRect(20, 80, 40, 10), 4, GCornersAll, GColorBlack)); #endif } void test_graphics_context_${BIT_DEPTH_NAME}__lock(void) { // Test all the setup test combinations as above setup_test(&context, false, 1, GColorBlack, GColorBlack, true); ASSERT_NO_CHANGE(graphics_draw_line(&context, GPoint(5, 5), GPoint(45, 10))); ASSERT_NO_CHANGE(graphics_draw_rect(&context, &GRect(10, 20, 40, 10))); ASSERT_NO_CHANGE(graphics_draw_circle(&context, GPoint(50, 50), 10)); ASSERT_NO_CHANGE(graphics_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4)); setup_test(&context, false, 2, GColorBlack, GColorBlack, true); ASSERT_NO_CHANGE(graphics_draw_line(&context, GPoint(5, 5), GPoint(45, 10))); ASSERT_NO_CHANGE(graphics_draw_rect(&context, &GRect(10, 20, 40, 10))); ASSERT_NO_CHANGE(graphics_draw_circle(&context, GPoint(50, 50), 10)); ASSERT_NO_CHANGE(graphics_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4)); setup_test(&context, false, SW_EVEN, GColorBlack, GColorBlack, true); ASSERT_NO_CHANGE(graphics_draw_line(&context, GPoint(5, 5), GPoint(45, 10))); ASSERT_NO_CHANGE(graphics_draw_rect(&context, &GRect(10, 20, 40, 10))); ASSERT_NO_CHANGE(graphics_draw_circle(&context, GPoint(50, 50), 10)); ASSERT_NO_CHANGE(graphics_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4)); setup_test(&context, false, SW_ODD, GColorBlack, GColorBlack, true); ASSERT_NO_CHANGE(graphics_draw_line(&context, GPoint(5, 5), GPoint(45, 10))); ASSERT_NO_CHANGE(graphics_draw_rect(&context, &GRect(10, 20, 40, 10))); ASSERT_NO_CHANGE(graphics_draw_circle(&context, GPoint(50, 50), 10)); ASSERT_NO_CHANGE(graphics_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4)); ASSERT_NO_CHANGE(graphics_fill_rect(&context, &GRect(10, 20, 40, 10))); ASSERT_NO_CHANGE(graphics_fill_circle(&context, GPoint(50, 50), 10)); ASSERT_NO_CHANGE(graphics_fill_round_rect(&context, &GRect(20, 80, 40, 10), 4, GCornersAll)); setup_test(&context, true, 1, GColorBlack, GColorBlack, true); ASSERT_NO_CHANGE(graphics_draw_line(&context, GPoint(5, 5), GPoint(45, 10))); ASSERT_NO_CHANGE(graphics_draw_rect(&context, &GRect(10, 20, 40, 10))); ASSERT_NO_CHANGE(graphics_draw_circle(&context, GPoint(50, 50), 10)); ASSERT_NO_CHANGE(graphics_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4)); setup_test(&context, true, 2, GColorBlack, GColorBlack, true); ASSERT_NO_CHANGE(graphics_draw_line(&context, GPoint(5, 5), GPoint(45, 10))); ASSERT_NO_CHANGE(graphics_draw_rect(&context, &GRect(10, 20, 40, 10))); ASSERT_NO_CHANGE(graphics_draw_circle(&context, GPoint(50, 50), 10)); ASSERT_NO_CHANGE(graphics_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4)); setup_test(&context, true, SW_EVEN, GColorBlack, GColorBlack, true); ASSERT_NO_CHANGE(graphics_draw_line(&context, GPoint(5, 5), GPoint(45, 10))); ASSERT_NO_CHANGE(graphics_draw_rect(&context, &GRect(10, 20, 40, 10))); ASSERT_NO_CHANGE(graphics_draw_circle(&context, GPoint(50, 50), 10)); ASSERT_NO_CHANGE(graphics_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4)); setup_test(&context, true, SW_ODD, GColorBlack, GColorBlack, true); ASSERT_NO_CHANGE(graphics_draw_line(&context, GPoint(5, 5), GPoint(45, 10))); ASSERT_NO_CHANGE(graphics_draw_rect(&context, &GRect(10, 20, 40, 10))); ASSERT_NO_CHANGE(graphics_draw_circle(&context, GPoint(50, 50), 10)); ASSERT_NO_CHANGE(graphics_draw_round_rect(&context, &GRect(20, 80, 40, 10), 4)); ASSERT_NO_CHANGE(graphics_fill_rect(&context, &GRect(10, 20, 40, 10))); ASSERT_NO_CHANGE(graphics_fill_circle(&context, GPoint(50, 50), 10)); ASSERT_NO_CHANGE(graphics_fill_round_rect(&context, &GRect(20, 80, 40, 10), 4, GCornersAll)); } void test_graphics_context_${BIT_DEPTH_NAME}__lock_context(void) { GDrawState draw_state; context.lock = true; // Stroke Color draw_state = graphics_context_get_drawing_state(&context); graphics_context_set_stroke_color(&context, GColorBlue); cl_assert(memcmp(&draw_state, &context.draw_state, sizeof(GDrawState)) == 0); // Fill Color draw_state = graphics_context_get_drawing_state(&context); graphics_context_set_fill_color(&context, GColorGreen); cl_assert(memcmp(&draw_state, &context.draw_state, sizeof(GDrawState)) == 0); // Compositing Mode draw_state = graphics_context_get_drawing_state(&context); graphics_context_set_compositing_mode(&context, GCompOpOr); cl_assert(memcmp(&draw_state, &context.draw_state, sizeof(GDrawState)) == 0); // Text Color draw_state = graphics_context_get_drawing_state(&context); graphics_context_set_text_color(&context, GColorRed); cl_assert(memcmp(&draw_state, &context.draw_state, sizeof(GDrawState)) == 0); // Antialiased draw_state = graphics_context_get_drawing_state(&context); graphics_context_set_antialiased(&context, true); cl_assert(memcmp(&draw_state, &context.draw_state, sizeof(GDrawState)) == 0); // Stroke Width draw_state = graphics_context_get_drawing_state(&context); graphics_context_set_stroke_width(&context, 11); cl_assert(memcmp(&draw_state, &context.draw_state, sizeof(GDrawState)) == 0); } void test_graphics_context_${BIT_DEPTH_NAME}__lock_framebuffer(void) { FrameBuffer fb = {}; framebuffer_init(&fb, &(GSize) {DISP_COLS, DISP_ROWS}); GContext ctx = {.dest_bitmap.info = { .format = GBITMAP_NATIVE_FORMAT, .version = GBITMAP_VERSION_CURRENT, }, .parent_framebuffer=&fb}; GBitmap *framebuffer = graphics_capture_frame_buffer(&ctx); cl_assert(ctx.lock == true); cl_assert_equal_p(framebuffer, &ctx.dest_bitmap); // Test releasing on any platform cl_assert(fb.is_dirty == false); graphics_release_frame_buffer(&ctx, framebuffer); cl_assert(ctx.lock == false); cl_assert(fb.is_dirty == true); }; void test_graphics_context_${BIT_DEPTH_NAME}__lock_framebuffer_8BitCircular(void) { // Test for locking of requested framebuffer format GContext ctx = {.dest_bitmap.info.format = GBitmapFormat8BitCircular}; GBitmap *bmp = graphics_capture_frame_buffer_format(&ctx, GBitmapFormat8BitCircular); cl_assert_equal_p(bmp, &ctx.dest_bitmap); cl_assert(ctx.lock == true); }; void test_graphics_context_${BIT_DEPTH_NAME}__lock_framebuffer_fails_from_8BitCircular(void) { // Test for locking of 8Bit Circular framebuffer when framebuffer is regular 8Bit GContext ctx = {.dest_bitmap.info.format = GBitmapFormat8BitCircular}; GBitmap *bmp = graphics_capture_frame_buffer_format(&ctx, GBitmapFormat8Bit); cl_assert(ctx.lock == false); cl_assert_equal_p(bmp, NULL); }; void test_graphics_context_${BIT_DEPTH_NAME}__lock_framebuffer_1Bit_on_8BitCircular_must_fail(void) { // Test for locking of 1Bit framebuffer when frambuffer is 8Bit Circular GContext ctx = {.dest_bitmap.info.format = GBitmapFormat8BitCircular}; GBitmap *bmp = graphics_capture_frame_buffer_format(&ctx, GBitmapFormat1Bit); cl_assert(ctx.lock == false); cl_assert_equal_p(bmp, NULL); }; void test_graphics_context_${BIT_DEPTH_NAME}__lock_framebuffer_2BitPalette_must_fail(void) { // Ensure that the code path for unsupported capture formats leaves the GContext unlocked. GContext ctx = {.dest_bitmap.info.format = GBitmapFormat8Bit}; GBitmap *bmp = graphics_capture_frame_buffer_format(&ctx, GBitmapFormat2BitPalette); cl_assert(ctx.lock == false); cl_assert_equal_p(bmp, NULL); }