pebble/tests/fw/graphics/test_graphics_context.template.c
2025-01-27 11:38:16 -08:00

847 lines
33 KiB
C

/*
* 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);
}