mirror of
https://github.com/google/pebble.git
synced 2025-03-19 18:41:21 +00:00
187 lines
6.3 KiB
C
187 lines
6.3 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/framebuffer.h"
|
|
#include "applib/graphics/graphics.h"
|
|
#include "resource/resource.h"
|
|
#include "resource/resource_ids.auto.h"
|
|
#include "util/graphics.h"
|
|
#include "util/size.h"
|
|
|
|
#include "clar.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
// Fakes
|
|
/////////////////////
|
|
|
|
#include "fixtures/load_test_resources.h"
|
|
|
|
// Stubs
|
|
/////////////////////
|
|
|
|
#include "stubs_analytics.h"
|
|
#include "stubs_app_state.h"
|
|
#include "stubs_bootbits.h"
|
|
#include "stubs_heap.h"
|
|
#include "stubs_logging.h"
|
|
#include "stubs_memory_layout.h"
|
|
#include "stubs_mutex.h"
|
|
#include "stubs_passert.h"
|
|
#include "stubs_pbl_malloc.h"
|
|
#include "stubs_pebble_tasks.h"
|
|
#include "stubs_print.h"
|
|
#include "stubs_prompt.h"
|
|
#include "stubs_serial.h"
|
|
#include "stubs_sleep.h"
|
|
#include "stubs_syscalls.h"
|
|
#include "stubs_task_watchdog.h"
|
|
#include "stubs_ui_window.h"
|
|
#include "stubs_unobstructed_area.h"
|
|
|
|
// Helper Functions
|
|
/////////////////////
|
|
#include "../graphics/test_graphics.h"
|
|
#include "../graphics/util.h"
|
|
|
|
// Setup and Teardown
|
|
////////////////////////////////////
|
|
|
|
static FrameBuffer *fb;
|
|
static GContext s_ctx;
|
|
static FontInfo s_font_info;
|
|
|
|
static GBitmap *s_dest_bitmap;
|
|
|
|
void test_emoji_fonts__initialize(void) {
|
|
fake_spi_flash_init(0, 0x1000000);
|
|
pfs_init(false);
|
|
pfs_format(true /* write erase headers */);
|
|
load_resource_fixture_in_flash(RESOURCES_FIXTURE_PATH, SYSTEM_RESOURCES_FIXTURE_NAME,
|
|
false /* is_next */);
|
|
|
|
memset(&s_font_info, 0, sizeof(s_font_info));
|
|
|
|
resource_init();
|
|
|
|
fb = malloc(sizeof(FrameBuffer));
|
|
framebuffer_init(fb, &(GSize) {DISP_COLS, DISP_ROWS});
|
|
|
|
test_graphics_context_init(&s_ctx, fb);
|
|
framebuffer_clear(fb);
|
|
}
|
|
|
|
void test_emoji_fonts__cleanup(void) {
|
|
free(fb);
|
|
fb = NULL;
|
|
|
|
gbitmap_destroy(s_dest_bitmap);
|
|
s_dest_bitmap = NULL;
|
|
}
|
|
|
|
// Helpers
|
|
//////////////////////
|
|
|
|
static char s_emoji_string[] =
|
|
"😄😃😀😊☺😉😍😘😚😗😙😜😝😛😳😁😔😌😒😞😣😢😂😭😥😪😰😅😓😩😫😨😱"
|
|
"😠😡😤😖😆😋😷😎😴😵😲😟😧😈👿😮😬😐😕😯😶😇😏😑😺😸😻😽😼🙀😿😹😾💩"
|
|
"👍👎👌👊✊✌👋✋👐👆👇👉👈🙌🙏☝👏💛💙💜💚❤💔💗💓💕💖💞💘💋🐥🎉💩🍻🍺"
|
|
"💪🔥🐵🙈→►★🎤🎥📷🎵🎁";
|
|
|
|
static void prv_render_text(GContext *ctx, const char *text, GFont const font, const GRect *box,
|
|
const GTextOverflowMode overflow_mode, const GTextAlignment alignment,
|
|
GTextLayoutCacheRef layout, bool render) {
|
|
if (render) {
|
|
graphics_draw_text(ctx, text, font, *box, overflow_mode, alignment, layout);
|
|
} else {
|
|
graphics_text_layout_get_max_used_size(ctx, text, font, *box, overflow_mode, alignment,
|
|
layout);
|
|
}
|
|
}
|
|
|
|
static GSize prv_draw_emoji(GContext *ctx, const GRect *bounds, GFont font, bool render) {
|
|
TextLayoutExtended layout = {
|
|
.line_spacing_delta = 2, // Give some space for the larger emojis
|
|
};
|
|
graphics_context_set_text_color(ctx, GColorBlack);
|
|
prv_render_text(ctx, s_emoji_string, font, bounds, GTextOverflowModeWordWrap,
|
|
GTextAlignmentLeft, (GTextLayoutCacheRef)&layout, true /* render */);
|
|
return layout.max_used_size;
|
|
}
|
|
|
|
void prv_prepare_canvas(GSize bitmap_size, GColor background_color) {
|
|
gbitmap_destroy(s_dest_bitmap);
|
|
|
|
s_dest_bitmap = gbitmap_create_blank(bitmap_size, GBitmapFormat8Bit);
|
|
|
|
s_ctx.dest_bitmap = *s_dest_bitmap;
|
|
s_ctx.draw_state.clip_box.size = bitmap_size;
|
|
s_ctx.draw_state.drawing_box.size = bitmap_size;
|
|
|
|
memset(s_dest_bitmap->addr, background_color.argb,
|
|
s_dest_bitmap->row_size_bytes * s_dest_bitmap->bounds.size.h);
|
|
}
|
|
|
|
void prv_prepare_canvas_and_render_emoji(ResourceId font_handle) {
|
|
// Calculate canvas size necessary
|
|
cl_assert(text_resources_init_font(0, font_handle, 0, &s_font_info));
|
|
|
|
const GPoint margin = { 10, 10 }; // Canvas margins
|
|
const int max_width = 300; // Canvas width, choose any visually pleasing width
|
|
const int max_height = 2000; // Large size protected from overflow and automatically truncated
|
|
const GSize max_size = { max_width, max_height };
|
|
|
|
// FIXME: PBL-34261 graphics_text_layout_get_max_used_size reports a max of 192px in a unit test
|
|
// with the default aplite framebuffer size. Work around this issue by creating a larger canvas.
|
|
prv_prepare_canvas(max_size, GColorWhite);
|
|
|
|
const GRect max_draw_frame = grect_inset_internal((GRect){ .size = max_size },
|
|
margin.x, margin.y);
|
|
const GSize used_size = prv_draw_emoji(&s_ctx, &max_draw_frame, &s_font_info,
|
|
false /* render */);
|
|
|
|
// Resize the canvas to the used size.
|
|
const GSize canvas_size = { max_width, used_size.h + 2 * margin.y };
|
|
prv_prepare_canvas(canvas_size, GColorWhite);
|
|
|
|
// Create the new canvas
|
|
const GRect draw_frame = grect_inset_internal((GRect){ .size = canvas_size },
|
|
margin.x, margin.y);
|
|
prv_draw_emoji(&s_ctx, &draw_frame, &s_font_info, true /* render */);
|
|
}
|
|
|
|
// Tests
|
|
//////////////////////
|
|
|
|
void test_emoji_fonts__gothic_14_emoji(void) {
|
|
prv_prepare_canvas_and_render_emoji(RESOURCE_ID_GOTHIC_14_EMOJI);
|
|
cl_check(gbitmap_pbi_eq(s_dest_bitmap, TEST_PBI_FILE));
|
|
}
|
|
|
|
void test_emoji_fonts__gothic_18_emoji(void) {
|
|
prv_prepare_canvas_and_render_emoji(RESOURCE_ID_GOTHIC_18_EMOJI);
|
|
cl_check(gbitmap_pbi_eq(s_dest_bitmap, TEST_PBI_FILE));
|
|
}
|
|
|
|
void test_emoji_fonts__gothic_24_emoji(void) {
|
|
prv_prepare_canvas_and_render_emoji(RESOURCE_ID_GOTHIC_24_EMOJI);
|
|
cl_check(gbitmap_pbi_eq(s_dest_bitmap, TEST_PBI_FILE));
|
|
}
|
|
|
|
void test_emoji_fonts__gothic_28_emoji(void) {
|
|
prv_prepare_canvas_and_render_emoji(RESOURCE_ID_GOTHIC_28_EMOJI);
|
|
cl_check(gbitmap_pbi_eq(s_dest_bitmap, TEST_PBI_FILE));
|
|
}
|