diff --git a/src/font_cache/font_cache.c b/src/font_cache/font_cache.c index 9754f352..44fea4d1 100644 --- a/src/font_cache/font_cache.c +++ b/src/font_cache/font_cache.c @@ -141,16 +141,22 @@ fnt_tag_from_path(String8 path) } //- rjf: allocate & push new node if we don't have an existing one - FNT_FontHashNode *new_node = 0; if(existing_node == 0) { + FP_Handle handle = fp_font_open(path); FNT_FontHashSlot *slot = &fnt_state->font_hash_table[slot_idx]; - new_node = push_array(fnt_state->permanent_arena, FNT_FontHashNode, 1); - new_node->tag = result; - new_node->handle = fp_font_open(path); - new_node->metrics = fp_metrics_from_font(new_node->handle); - new_node->path = push_str8_copy(fnt_state->permanent_arena, path); - SLLQueuePush_N(slot->first, slot->last, new_node, hash_next); + existing_node = push_array(fnt_state->permanent_arena, FNT_FontHashNode, 1); + existing_node->tag = result; + existing_node->handle = handle; + existing_node->metrics = fp_metrics_from_font(existing_node->handle); + existing_node->path = push_str8_copy(fnt_state->permanent_arena, path); + SLLQueuePush_N(slot->first, slot->last, existing_node, hash_next); + } + + //- rjf: tag result must be zero if this is not a valid font + if(fp_handle_match(existing_node->handle, fp_handle_zero())) + { + MemoryZeroStruct(&result); } //- rjf: return diff --git a/src/font_provider/dwrite/font_provider_dwrite.c b/src/font_provider/dwrite/font_provider_dwrite.c index 4770ebba..ebf81ff4 100644 --- a/src/font_provider/dwrite/font_provider_dwrite.c +++ b/src/font_provider/dwrite/font_provider_dwrite.c @@ -318,18 +318,64 @@ fp_font_open(String8 path) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - String16 path16 = str16_from_8(scratch.arena, path); FP_DWrite_Font font = {0}; HRESULT error = 0; - //- rjf: open font file reference - error = IDWriteFactory_CreateFontFileReference(fp_dwrite_state->factory, (WCHAR *)path16.str, 0, &font.file); + //- rjf: build initial path task + typedef struct PathTask PathTask; + struct PathTask + { + PathTask *next; + String8 path; + }; + PathTask start_task = {0, path}; + PathTask *first_task = &start_task; + PathTask *last_task = first_task; - //- rjf: open font face - error = IDWriteFactory_CreateFontFace(fp_dwrite_state->factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &font.file, 0, DWRITE_FONT_SIMULATIONS_NONE, &font.face); + //- rjf: try to open font + for(PathTask *t = first_task; t != 0 && font.file == 0; t = t->next) + { + String16 path16 = str16_from_8(scratch.arena, t->path); + error = IDWriteFactory_CreateFontFileReference(fp_dwrite_state->factory, (WCHAR *)path16.str, 0, &font.file); + error = IDWriteFactory_CreateFontFace(fp_dwrite_state->factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &font.file, 0, DWRITE_FONT_SIMULATIONS_NONE, &font.face); + + // rjf: failure trying just the normal path? -> generate new tasks that search in system folders + if(t == first_task && font.file == 0) + { + // rjf: generate task for user-installed fonts + { + HKEY reg_key = 0; + LSTATUS status = 0; + char name[256] = {0}; + char data[256] = {0}; + DWORD name_size = sizeof(name); + DWORD data_size = sizeof(data); + DWORD type = 0; + status = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\\Fonts", 0, KEY_QUERY_VALUE, ®_key); + status = RegEnumValueA(reg_key, 0, name, &name_size, 0, &type, data, &data_size); + String8 user_fonts_path = str8_cstring(data); + PathTask *task = push_array(scratch.arena, PathTask, 1); + task->path = push_str8f(scratch.arena, "%s/%S", user_fonts_path, path); + SLLQueuePush(first_task, last_task, task); + } + + // rjf: generate task for windows directory (C:/Windows/Fonts, generally) + { + char windows_path[256] = {0}; + GetWindowsDirectoryA(windows_path, sizeof(windows_path)); + PathTask *task = push_array(scratch.arena, PathTask, 1); + task->path = push_str8f(scratch.arena, "%s/Fonts/%S", windows_path, path); + SLLQueuePush(first_task, last_task, task); + } + } + } //- rjf: handlify & return - FP_Handle handle = fp_dwrite_handle_from_font(font); + FP_Handle handle = {0}; + if(font.file != 0) + { + handle = fp_dwrite_handle_from_font(font); + } scratch_end(scratch); ProfEnd(); return handle; diff --git a/src/raddbg/generated/raddbg.meta.c b/src/raddbg/generated/raddbg.meta.c index 0a4ace89..339f75e6 100644 --- a/src/raddbg/generated/raddbg.meta.c +++ b/src/raddbg/generated/raddbg.meta.c @@ -377,7 +377,7 @@ RD_VocabInfo rd_vocab_info_table[319] = RD_NameSchemaInfo rd_name_schema_info_table[22] = { -{str8_lit_comp("user"), str8_lit_comp("x:\n{\n //- rjf: animations\n @default(1) 'hover_animations': bool,\n @default(1) 'press_animations': bool,\n @default(0) 'focus_animations': bool,\n @default(1) 'tooltip_animations': bool,\n @default(1) 'menu_animations': bool,\n @default(1) 'scrolling_animations': bool,\n\n //- rjf: fonts\n 'main_font': string,\n 'code_font': string,\n\n //- rjf: colors\n @display_name('Color Preset')\n 'color_preset': string,\n @display_name('Color File')\n 'color_file': path,\n @display_name('Colors')\n 'colors': query,\n\n //- rjf: thread & breakpoint decorations\n @default(1) @display_name('Thread Lines') @description(\"Controls whether or not a long horizontal line is drawn before the next line or instruction that the selected thread will execute in source and disassembly views.\")\n 'thread_lines': bool,\n @default(1) @display_name('Thread Glow') @description(\"Controls whether or not a glowing effect is drawn on the selected thread in source and disassembly views.\")\n 'thread_glow': bool,\n @default(1) @display_name('Breakpoint Lines') @description(\"Controls whether or not a long horizontal line is drawn before the line or instruction at which a breakpoint is placed, in source and disassembly views.\")\n 'breakpoint_lines': bool,\n @default(1) @display_name('Breakpoint Glow') @description(\"Controls whether or not a glowing effect is drawn on breakpoints in source and disassembly views.\")\n 'breakpoint_glow': bool,\n\n //- rjf: occluding background settings\n @default(0) @display_name('Opaque Backgrounds') @description(\"Controls whether or not all floating background colors are forced to be fully opaque.\")\n 'opaque_backgrounds': bool,\n @default(1) @display_name('Background Blur') @description(\"Controls whether or not occluded regions behind floating elements are blurred.\")\n 'background_blur': bool,\n\n //- rjf: appearance settings\n @default(1) @display_name('Drop Shadows') @description(\"Controls whether or not drop shadows are drawn.\")\n 'drop_shadows': bool,\n @default(1.f) @display_name('Rounded Corner Amount') @description(\"Controls the degree to which UI corners are rounded.\")\n 'rounded_corner_amount': @range[0, 1] f32,\n\n //- rjf: code formatting settings\n @default(2) @display_name('User Tab Width') 'tab_width': @range[1, 32] u64,\n\n //- rjf: windows style menu bar\n @default(1) @display_name('Focus Menu Bar With Alt') @description(\"Mimics standard Windows behavior of focusing the menu bar using the Alt key.\")\n 'focus_menu_bar_with_alt': bool,\n}\n")}, +{str8_lit_comp("user"), str8_lit_comp("x:\n{\n //- rjf: animations\n @default(1) 'hover_animations': bool,\n @default(1) 'press_animations': bool,\n @default(0) 'focus_animations': bool,\n @default(1) 'tooltip_animations': bool,\n @default(1) 'menu_animations': bool,\n @default(1) 'scrolling_animations': bool,\n\n //- rjf: fonts\n @display_name('UI Font') @description(\"The name or path to the font used when displaying non-code UI elements.\")\n 'main_font': string,\n @display_name('Code Font') @description(\"The name or path to the font used when displaying code.\")\n 'code_font': string,\n\n //- rjf: colors\n @display_name('Color Preset')\n 'color_preset': string,\n @display_name('Color File')\n 'color_file': path,\n @display_name('Colors')\n 'colors': query,\n\n //- rjf: thread & breakpoint decorations\n @default(1) @display_name('Thread Lines') @description(\"Controls whether or not a long horizontal line is drawn before the next line or instruction that the selected thread will execute in source and disassembly views.\")\n 'thread_lines': bool,\n @default(1) @display_name('Thread Glow') @description(\"Controls whether or not a glowing effect is drawn on the selected thread in source and disassembly views.\")\n 'thread_glow': bool,\n @default(1) @display_name('Breakpoint Lines') @description(\"Controls whether or not a long horizontal line is drawn before the line or instruction at which a breakpoint is placed, in source and disassembly views.\")\n 'breakpoint_lines': bool,\n @default(1) @display_name('Breakpoint Glow') @description(\"Controls whether or not a glowing effect is drawn on breakpoints in source and disassembly views.\")\n 'breakpoint_glow': bool,\n\n //- rjf: occluding background settings\n @default(0) @display_name('Opaque Backgrounds') @description(\"Controls whether or not all floating background colors are forced to be fully opaque.\")\n 'opaque_backgrounds': bool,\n @default(1) @display_name('Background Blur') @description(\"Controls whether or not occluded regions behind floating elements are blurred.\")\n 'background_blur': bool,\n\n //- rjf: appearance settings\n @default(1) @display_name('Drop Shadows') @description(\"Controls whether or not drop shadows are drawn.\")\n 'drop_shadows': bool,\n @default(1.f) @display_name('Rounded Corner Amount') @description(\"Controls the degree to which UI corners are rounded.\")\n 'rounded_corner_amount': @range[0, 1] f32,\n\n //- rjf: code formatting settings\n @default(2) @display_name('User Tab Width') 'tab_width': @range[1, 32] u64,\n\n //- rjf: windows style menu bar\n @default(1) @display_name('Focus Menu Bar With Alt') @description(\"Mimics standard Windows behavior of focusing the menu bar using the Alt key.\")\n 'focus_menu_bar_with_alt': bool,\n}\n")}, {str8_lit_comp("project"), str8_lit_comp("x:\n{\n @default(2) @display_name('Project Tab Width') 'tab_width': @range[1, 32] u64,\n @default(1) @display_name(\"Break On Win32 Control-C Exceptions\") @description(\"Code: 0x40010005\")\n win32_ctrl_c: bool;\n @default(1) @display_name(\"Break On Win32 Control-Break Exceptions\") @description(\"Code: 0x40010008\")\n win32_ctrl_break: bool;\n @default(0) @display_name(\"Break On Win32 WinRT Originate Error Exceptions\") @description(\"Code: 0x40080201\")\n win32_win_rt_originate_error: bool;\n @default(0) @display_name(\"Break On Win32 WinRT Transform Error Exceptions\") @description(\"Code: 0x40080202\")\n win32_win_rt_transform_error: bool;\n @default(0) @display_name(\"Break On Win32 RPC Call Cancelled Exceptions\") @description(\"Code: 0x0000071a\")\n win32_rpc_call_cancelled: bool;\n @default(0) @display_name(\"Break On Win32 Data Type Misalignment Exceptions\") @description(\"Code: 0x80000002\")\n win32_datatype_misalignment: bool;\n @default(1) @display_name(\"Break On Win32 Access Violation Exceptions\") @description(\"Code: 0xc0000005\")\n win32_access_violation: bool;\n @default(0) @display_name(\"Break On Win32 In Page Error Exceptions\") @description(\"Code: 0xc0000006\")\n win32_in_page_error: bool;\n @default(1) @display_name(\"Break On Win32 Invalid Handle Specified Exceptions\") @description(\"Code: 0xc0000008\")\n win32_invalid_handle: bool;\n @default(0) @display_name(\"Break On Win32 Not Enough Quota Exceptions\") @description(\"Code: 0xc0000017\")\n win32_not_enough_quota: bool;\n @default(0) @display_name(\"Break On Win32 Illegal Instruction Exceptions\") @description(\"Code: 0xc000001d\")\n win32_illegal_instruction: bool;\n @default(0) @display_name(\"Break On Win32 Cannot Continue From Exception Exceptions\") @description(\"Code: 0xc0000025\")\n win32_cannot_continue_exception: bool;\n @default(0) @display_name(\"Break On Win32 Invalid Exception Disposition Returned By Handler Exceptions\") @description(\"Code: 0xc0000026\")\n win32_invalid_exception_disposition: bool;\n @default(0) @display_name(\"Break On Win32 Array Bounds Exceeded Exceptions\") @description(\"Code: 0xc000008c\")\n win32_array_bounds_exceeded: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Denormal Operand Exceptions\") @description(\"Code: 0xc000008d\")\n win32_floating_point_denormal_operand: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Division By Zero Exceptions\") @description(\"Code: 0xc000008e\")\n win32_floating_point_division_by_zero: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Inexact Result Exceptions\") @description(\"Code: 0xc000008f\")\n win32_floating_point_inexact_result: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Invalid Operation Exceptions\") @description(\"Code: 0xc0000090\")\n win32_floating_point_invalid_operation: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Overflow Exceptions\") @description(\"Code: 0xc0000091\")\n win32_floating_point_overflow: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Stack Check Exceptions\") @description(\"Code: 0xc0000092\")\n win32_floating_point_stack_check: bool;\n @default(0) @display_name(\"Break On Win32 Floating-Point Underflow Exceptions\") @description(\"Code: 0xc0000093\")\n win32_floating_point_underflow: bool;\n @default(0) @display_name(\"Break On Win32 Integer Division By Zero Exceptions\") @description(\"Code: 0xc0000094\")\n win32_integer_division_by_zero: bool;\n @default(0) @display_name(\"Break On Win32 Integer Overflow Exceptions\") @description(\"Code: 0xc0000095\")\n win32_integer_overflow: bool;\n @default(0) @display_name(\"Break On Win32 Privileged Instruction Exceptions\") @description(\"Code: 0xc0000096\")\n win32_privileged_instruction: bool;\n @default(0) @display_name(\"Break On Win32 Stack Overflow Exceptions\") @description(\"Code: 0xc00000fd\")\n win32_stack_overflow: bool;\n @default(0) @display_name(\"Break On Win32 Unable To Locate DLL Exceptions\") @description(\"Code: 0xc0000135\")\n win32_unable_to_locate_dll: bool;\n @default(0) @display_name(\"Break On Win32 Ordinal Not Found Exceptions\") @description(\"Code: 0xc0000138\")\n win32_ordinal_not_found: bool;\n @default(0) @display_name(\"Break On Win32 Entry Point Not Found Exceptions\") @description(\"Code: 0xc0000139\")\n win32_entry_point_not_found: bool;\n @default(0) @display_name(\"Break On Win32 DLL Initialization Failed Exceptions\") @description(\"Code: 0xc0000142\")\n win32_dll_initialization_failed: bool;\n @default(0) @display_name(\"Break On Win32 Floating Point SSE Multiple Faults Exceptions\") @description(\"Code: 0xc00002b4\")\n win32_floating_point_sse_multiple_faults: bool;\n @default(0) @display_name(\"Break On Win32 Floating Point SSE Multiple Traps Exceptions\") @description(\"Code: 0xc00002b5\")\n win32_floating_point_sse_multiple_traps: bool;\n @default(1) @display_name(\"Break On Win32 Assertion Failed Exceptions\") @description(\"Code: 0xc0000420\")\n win32_assertion_failed: bool;\n @default(0) @display_name(\"Break On Win32 Module Not Found Exceptions\") @description(\"Code: 0xc06d007e\")\n win32_module_not_found: bool;\n @default(0) @display_name(\"Break On Win32 Procedure Not Found Exceptions\") @description(\"Code: 0xc06d007f\")\n win32_procedure_not_found: bool;\n @default(1) @display_name(\"Break On Win32 Sanitizer Error Detected Exceptions\") @description(\"Code: 0xe073616e\")\n win32_sanitizer_error_detected: bool;\n @default(0) @display_name(\"Break On Win32 Sanitizer Raw Access Violation Exceptions\") @description(\"Code: 0xe0736171\")\n win32_sanitizer_raw_access_violation: bool;\n @default(1) @display_name(\"Break On Win32 DirectX Debug Layer Exceptions\") @description(\"Code: 0x0000087a\")\n win32_directx_debug_layer: bool;\n}\n")}, {str8_lit_comp("color"), str8_lit_comp("@collection_commands(add_color, import_colors) x:\n{\n @display_name('Tags') tags: string,\n @display_name('Value') value: @color @hex u32,\n}\n")}, {str8_lit_comp("window"), str8_lit_comp("x:\n{\n //- rjf: text rasterization settings\n @default(1) @display_name('Smooth UI Text') @description(\"Controls whether or not UI text is fully anti-aliased, for a smoother appearance.\")\n 'smooth_ui_text': bool,\n @default(1) @display_name('Hint UI Text') @description(\"Controls whether or not UI text is hinted, for better text readability at small sizes.\")\n 'hint_ui_text': bool,\n @default(0) @display_name('Smooth Code Text') @description(\"Controls whether or not code text is fully anti-aliased, for a smoother appearance.\")\n 'smooth_code_text': bool,\n @default(1) @display_name('Hint Code Text') @description(\"Controls whether or not code text is hinted, for better text readability at small sizes.\")\n 'hint_code_text': bool,\n @default(11) @display_name('Window Font Size') @description(\"Controls the window's default font size. Does not apply to tabs with their own font size set.\")\n 'font_size': @range[6, 72] u64,\n\n //- rjf: size settings\n @default(3.f) @display_name('Window Row Height') @description(\"Controls the window's default row height, in multiples of the font size. Does not apply to tabs with their own row height set.\")\n 'row_height': @range[1.75f, 5.f] f32,\n @default(3.f) @description(\"Controls the height of tabs, in multiples of the font size.\")\n 'tab_height': @range[1.75f, 5.f] f32,\n}\n")}, diff --git a/src/raddbg/raddbg.mdesk b/src/raddbg/raddbg.mdesk index 554dbcaf..77fb96be 100644 --- a/src/raddbg/raddbg.mdesk +++ b/src/raddbg/raddbg.mdesk @@ -225,8 +225,10 @@ RD_VocabTable: @default(1) 'scrolling_animations': bool, //- rjf: fonts - 'main_font': string, - 'code_font': string, + @display_name('UI Font') @description("The name or path to the font used when displaying non-code UI elements.") + 'main_font': string, + @display_name('Code Font') @description("The name or path to the font used when displaying code.") + 'code_font': string, //- rjf: colors @display_name('Color Preset') diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index c180c27a..973e5741 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -10394,7 +10394,11 @@ rd_font_from_slot(RD_FontSlot slot) // rjf: map name -> tag FNT_Tag result = {0}; - if(font_name.size == 0) + if(font_name.size != 0) + { + result = fnt_tag_from_path(font_name); + } + if(font_name.size == 0 || fnt_tag_match(fnt_tag_zero(), result)) { switch(slot) { @@ -10404,11 +10408,6 @@ rd_font_from_slot(RD_FontSlot slot) case RD_FontSlot_Icons:{result = fnt_tag_from_static_data_string(&rd_icon_font_bytes);}break; } } - else - { - // TODO(rjf): need to handle "system font names" here. - result = fnt_tag_from_path(font_name); - } return result; } diff --git a/src/raddbg/raddbg_main.c b/src/raddbg/raddbg_main.c index 4783e43e..a6c1515f 100644 --- a/src/raddbg/raddbg_main.c +++ b/src/raddbg/raddbg_main.c @@ -207,10 +207,6 @@ //////////////////////////////// //~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup) // -// [ ] Setting the code_font/main_font values to a font name doesn't work. -// Should probably make note that you have to set it to a path to a TTF, -// since that's not normally how Windows fonts work. -// // [ ] "root" concept in hash store, which buckets keys & allows usage code to // jettison a collection of keys in retained mode fashion // @@ -422,6 +418,9 @@ // size dynamically // [x] automatically start search query with selected text // [x] @feature processor/data breakpoints +// [x] Setting the code_font/main_font values to a font name doesn't work. +// Should probably make note that you have to set it to a path to a TTF, +// since that's not normally how Windows fonts work. //////////////////////////////// //~ rjf: Build Options