gdiplus: Implement font linking for gdiplus.
This commit is contained in:
parent
d68a9d1213
commit
ba4681e776
4 changed files with 158 additions and 21 deletions
|
@ -1,6 +1,6 @@
|
|||
MODULE = gdiplus.dll
|
||||
IMPORTLIB = gdiplus
|
||||
IMPORTS = uuid shlwapi ole32 oleaut32 user32 gdi32
|
||||
IMPORTS = uuid shlwapi ole32 oleaut32 user32 gdi32 mlang
|
||||
DELAYIMPORTS = windowscodecs
|
||||
|
||||
SOURCES = \
|
||||
|
|
|
@ -606,8 +606,22 @@ static inline const void *buffer_read(struct memory_buffer *mbuf, INT size)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Represents a string section and the font it should use. */
|
||||
struct gdip_font_link_section {
|
||||
struct list entry;
|
||||
DWORD start; /* The starting index of the string where the font applies. */
|
||||
DWORD end; /* The end index of the string. */
|
||||
GpFont *font;
|
||||
};
|
||||
|
||||
struct gdip_font_link_info {
|
||||
GDIPCONST GpFont *base_font;
|
||||
struct list sections;
|
||||
};
|
||||
|
||||
|
||||
typedef GpStatus (*gdip_format_string_callback)(GpGraphics *graphics,
|
||||
GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
|
||||
GDIPCONST WCHAR *string, INT index, INT length, struct gdip_font_link_info *sections,
|
||||
GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
|
||||
INT lineno, const RectF *bounds, INT *underlined_indexes,
|
||||
INT underlined_index_count, void *user_data);
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "winreg.h"
|
||||
#include "shlwapi.h"
|
||||
|
||||
#include "mlang.h"
|
||||
#include "gdiplus.h"
|
||||
#include "gdiplus_private.h"
|
||||
#include "wine/debug.h"
|
||||
|
@ -5197,6 +5198,110 @@ GpStatus WINGDIPAPI GdipIsVisibleRectI(GpGraphics *graphics, INT x, INT y, INT w
|
|||
return GdipIsVisibleRect(graphics, (REAL)x, (REAL)y, (REAL)width, (REAL)height, result);
|
||||
}
|
||||
|
||||
/* Populates gdip_font_link_info struct based on the base_font and input string */
|
||||
static void generate_font_link_info(GpGraphics *graphics, WCHAR *string, DWORD length, GDIPCONST GpFont *base_font,
|
||||
struct gdip_font_link_info *font_link_info)
|
||||
{
|
||||
IUnknown *unk;
|
||||
IMLangFontLink *iMLFL;
|
||||
GpFont *gpfont;
|
||||
HFONT map_hfont, hfont, old_font;
|
||||
LONG processed, progress = 0;
|
||||
struct gdip_font_link_section *section;
|
||||
DWORD font_codepages, string_codepages;
|
||||
|
||||
list_init(&font_link_info->sections);
|
||||
font_link_info->base_font = base_font;
|
||||
|
||||
GetGlobalFontLinkObject((void**)&unk);
|
||||
IUnknown_QueryInterface(unk, &IID_IMLangFontLink, (void**)&iMLFL);
|
||||
IUnknown_Release(unk);
|
||||
|
||||
get_font_hfont(graphics, base_font, NULL, &hfont, NULL, NULL);
|
||||
IMLangFontLink_GetFontCodePages(iMLFL, graphics->hdc, hfont, &font_codepages);
|
||||
|
||||
while (progress < length)
|
||||
{
|
||||
section = calloc(1, sizeof(*section));
|
||||
section->start = progress;
|
||||
IMLangFontLink_GetStrCodePages(iMLFL, &string[progress], length - progress,
|
||||
font_codepages, &string_codepages, &processed);
|
||||
|
||||
if (font_codepages & string_codepages)
|
||||
{
|
||||
section->font = (GpFont *)base_font;
|
||||
}
|
||||
else
|
||||
{
|
||||
IMLangFontLink_MapFont(iMLFL, graphics->hdc, string_codepages, hfont, &map_hfont);
|
||||
old_font = SelectObject(graphics->hdc, map_hfont);
|
||||
GdipCreateFontFromDC(graphics->hdc, &gpfont);
|
||||
SelectObject(graphics->hdc, old_font);
|
||||
IMLangFontLink_ReleaseFont(iMLFL, map_hfont);
|
||||
section->font = gpfont;
|
||||
}
|
||||
|
||||
section->end = section->start + processed;
|
||||
list_add_tail(&font_link_info->sections, §ion->entry);
|
||||
progress += processed;
|
||||
}
|
||||
|
||||
DeleteObject(hfont);
|
||||
IMLangFontLink_Release(iMLFL);
|
||||
}
|
||||
|
||||
static void font_link_get_text_extent_point(struct gdip_font_link_info *font_link_info, GpGraphics *graphics, LPCWSTR string,
|
||||
INT index, int length, int max_ext, LPINT fit, SIZE *size)
|
||||
{
|
||||
DWORD to_measure_length;
|
||||
HFONT hfont, oldhfont;
|
||||
SIZE sizeaux = { 0 };
|
||||
int i = index, fitaux = 0;
|
||||
struct gdip_font_link_section *section;
|
||||
|
||||
size->cx = 0;
|
||||
size->cy = 0;
|
||||
|
||||
if (fit)
|
||||
*fit = 0;
|
||||
|
||||
LIST_FOR_EACH_ENTRY(section, &font_link_info->sections, struct gdip_font_link_section, entry)
|
||||
{
|
||||
if (i >= section->end) continue;
|
||||
|
||||
to_measure_length = min(length - (i - index), section->end - i);
|
||||
|
||||
get_font_hfont(graphics, section->font, NULL, &hfont, NULL, NULL);
|
||||
oldhfont = SelectObject(graphics->hdc, hfont);
|
||||
GetTextExtentExPointW(graphics->hdc, &string[i], to_measure_length, max_ext, &fitaux, NULL, &sizeaux);
|
||||
SelectObject(graphics->hdc, oldhfont);
|
||||
DeleteObject(hfont);
|
||||
|
||||
max_ext -= sizeaux.cx;
|
||||
if (fit)
|
||||
*fit += fitaux;
|
||||
size->cx += sizeaux.cx;
|
||||
size->cy = max(size->cy, sizeaux.cy);
|
||||
|
||||
i += to_measure_length;
|
||||
if ((i - index) >= length || fitaux < to_measure_length) break;
|
||||
}
|
||||
}
|
||||
|
||||
static void release_font_link_info(struct gdip_font_link_info *font_link_info)
|
||||
{
|
||||
struct list *entry;
|
||||
|
||||
while ((entry = list_head(&font_link_info->sections)))
|
||||
{
|
||||
struct gdip_font_link_section *section = LIST_ENTRY(entry, struct gdip_font_link_section, entry);
|
||||
list_remove(entry);
|
||||
if (section->font != font_link_info->base_font)
|
||||
GdipDeleteFont(section->font);
|
||||
free(section);
|
||||
}
|
||||
}
|
||||
|
||||
GpStatus gdip_format_string(GpGraphics *graphics,
|
||||
GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font,
|
||||
GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, int ignore_empty_clip,
|
||||
|
@ -5213,6 +5318,7 @@ GpStatus gdip_format_string(GpGraphics *graphics,
|
|||
INT *hotkeyprefix_offsets=NULL;
|
||||
INT hotkeyprefix_count=0;
|
||||
INT hotkeyprefix_pos=0, hotkeyprefix_end_pos=0;
|
||||
struct gdip_font_link_info font_link_info = { 0 };
|
||||
BOOL seen_prefix = FALSE, unixstyle_newline = TRUE;
|
||||
|
||||
if(length == -1) length = lstrlenW(string);
|
||||
|
@ -5278,9 +5384,10 @@ GpStatus gdip_format_string(GpGraphics *graphics,
|
|||
|
||||
halign = format->align;
|
||||
|
||||
generate_font_link_info(graphics, stringdup, length, font, &font_link_info);
|
||||
|
||||
while(sum < length){
|
||||
GetTextExtentExPointW(graphics->hdc, stringdup + sum, length - sum,
|
||||
nwidth, &fit, NULL, &size);
|
||||
font_link_get_text_extent_point(&font_link_info, graphics, stringdup, sum, length - sum, nwidth, &fit, &size);
|
||||
fitcpy = fit;
|
||||
|
||||
if(fit == 0)
|
||||
|
@ -5328,8 +5435,7 @@ GpStatus gdip_format_string(GpGraphics *graphics,
|
|||
else
|
||||
lineend = fit;
|
||||
|
||||
GetTextExtentExPointW(graphics->hdc, stringdup + sum, lineend,
|
||||
nwidth, &j, NULL, &size);
|
||||
font_link_get_text_extent_point(&font_link_info, graphics, stringdup, sum, lineend, nwidth, &j, &size);
|
||||
|
||||
bounds.Width = size.cx;
|
||||
|
||||
|
@ -5363,7 +5469,7 @@ GpStatus gdip_format_string(GpGraphics *graphics,
|
|||
break;
|
||||
|
||||
stat = callback(graphics, stringdup, sum, lineend,
|
||||
font, rect, format, lineno, &bounds,
|
||||
&font_link_info, rect, format, lineno, &bounds,
|
||||
&hotkeyprefix_offsets[hotkeyprefix_pos],
|
||||
hotkeyprefix_end_pos-hotkeyprefix_pos, user_data);
|
||||
|
||||
|
@ -5394,6 +5500,7 @@ GpStatus gdip_format_string(GpGraphics *graphics,
|
|||
break;
|
||||
}
|
||||
|
||||
release_font_link_info(&font_link_info);
|
||||
free(stringdup);
|
||||
free(hotkeyprefix_offsets);
|
||||
|
||||
|
@ -5429,7 +5536,8 @@ struct measure_ranges_args {
|
|||
};
|
||||
|
||||
static GpStatus measure_ranges_callback(GpGraphics *graphics,
|
||||
GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
|
||||
GDIPCONST WCHAR *string, INT index, INT length,
|
||||
struct gdip_font_link_info *font_link_info,
|
||||
GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
|
||||
INT lineno, const RectF *bounds, INT *underlined_indexes,
|
||||
INT underlined_index_count, void *user_data)
|
||||
|
@ -5450,12 +5558,10 @@ static GpStatus measure_ranges_callback(GpGraphics *graphics,
|
|||
range_rect.Y = bounds->Y / args->rel_height;
|
||||
range_rect.Height = bounds->Height / args->rel_height;
|
||||
|
||||
GetTextExtentExPointW(graphics->hdc, string + index, range_start - index,
|
||||
INT_MAX, NULL, NULL, &range_size);
|
||||
font_link_get_text_extent_point(font_link_info, graphics, string, index, range_start - index, INT_MAX, NULL, &range_size);
|
||||
range_rect.X = (bounds->X + range_size.cx) / args->rel_width;
|
||||
|
||||
GetTextExtentExPointW(graphics->hdc, string + index, range_end - index,
|
||||
INT_MAX, NULL, NULL, &range_size);
|
||||
font_link_get_text_extent_point(font_link_info, graphics, string, index, range_end - index, INT_MAX, NULL, &range_size);
|
||||
range_rect.Width = (bounds->X + range_size.cx) / args->rel_width - range_rect.X;
|
||||
|
||||
stat = GdipCombineRegionRect(args->regions[i], &range_rect, CombineModeUnion);
|
||||
|
@ -5554,7 +5660,8 @@ struct measure_string_args {
|
|||
};
|
||||
|
||||
static GpStatus measure_string_callback(GpGraphics *graphics,
|
||||
GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
|
||||
GDIPCONST WCHAR *string, INT index, INT length,
|
||||
struct gdip_font_link_info *font_link_info,
|
||||
GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
|
||||
INT lineno, const RectF *bounds, INT *underlined_indexes,
|
||||
INT underlined_index_count, void *user_data)
|
||||
|
@ -5672,21 +5779,37 @@ struct draw_string_args {
|
|||
};
|
||||
|
||||
static GpStatus draw_string_callback(GpGraphics *graphics,
|
||||
GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
|
||||
GDIPCONST WCHAR *string, INT index, INT length,
|
||||
struct gdip_font_link_info *font_link_info,
|
||||
GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
|
||||
INT lineno, const RectF *bounds, INT *underlined_indexes,
|
||||
INT underlined_index_count, void *user_data)
|
||||
{
|
||||
struct draw_string_args *args = user_data;
|
||||
int i = index;
|
||||
PointF position;
|
||||
GpStatus stat;
|
||||
SIZE size;
|
||||
DWORD to_draw_length;
|
||||
struct gdip_font_link_section *section;
|
||||
GpStatus stat = Ok;
|
||||
|
||||
position.X = args->x + bounds->X / args->rel_width;
|
||||
position.Y = args->y + bounds->Y / args->rel_height + args->ascent;
|
||||
|
||||
stat = draw_driver_string(graphics, &string[index], length, font, format,
|
||||
args->brush, &position,
|
||||
DriverStringOptionsCmapLookup|DriverStringOptionsRealizedAdvance, NULL);
|
||||
LIST_FOR_EACH_ENTRY(section, &font_link_info->sections, struct gdip_font_link_section, entry)
|
||||
{
|
||||
if (i >= section->end) continue;
|
||||
|
||||
to_draw_length = min(length - (i - index), section->end - i);
|
||||
TRACE("index %d, todraw %ld, used %s\n", i, to_draw_length, section->font == font_link_info->base_font ? "base font" : "map");
|
||||
font_link_get_text_extent_point(font_link_info, graphics, string, i, to_draw_length, 0, NULL, &size);
|
||||
stat = draw_driver_string(graphics, &string[i], to_draw_length,
|
||||
section->font, format, args->brush, &position,
|
||||
DriverStringOptionsCmapLookup|DriverStringOptionsRealizedAdvance, NULL);
|
||||
position.X += size.cx / args->rel_width;
|
||||
i += to_draw_length;
|
||||
if (stat != Ok || (i - index) >= length) break;
|
||||
}
|
||||
|
||||
if (stat == Ok && underlined_index_count)
|
||||
{
|
||||
|
@ -5705,10 +5828,10 @@ static GpStatus draw_string_callback(GpGraphics *graphics,
|
|||
SIZE text_size;
|
||||
INT ofs = underlined_indexes[i] - index;
|
||||
|
||||
GetTextExtentExPointW(graphics->hdc, string + index, ofs, INT_MAX, NULL, NULL, &text_size);
|
||||
font_link_get_text_extent_point(font_link_info, graphics, string, index, ofs, INT_MAX, NULL, &text_size);
|
||||
start_x = text_size.cx / args->rel_width;
|
||||
|
||||
GetTextExtentExPointW(graphics->hdc, string + index, ofs+1, INT_MAX, NULL, NULL, &text_size);
|
||||
font_link_get_text_extent_point(font_link_info, graphics, string, index, ofs+1, INT_MAX, NULL, &text_size);
|
||||
end_x = text_size.cx / args->rel_width;
|
||||
|
||||
GdipFillRectangle(graphics, (GpBrush*)args->brush, position.X+start_x, underline_y, end_x-start_x, underline_height);
|
||||
|
|
|
@ -998,7 +998,7 @@ struct format_string_args
|
|||
};
|
||||
|
||||
static GpStatus format_string_callback(GpGraphics *graphics,
|
||||
GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
|
||||
GDIPCONST WCHAR *string, INT index, INT length, struct gdip_font_link_info *font_link_info,
|
||||
GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
|
||||
INT lineno, const RectF *bounds, INT *underlined_indexes,
|
||||
INT underlined_index_count, void *priv)
|
||||
|
|
Loading…
Add table
Reference in a new issue