Skip to content
This repository was archived by the owner on Mar 7, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 88 additions & 83 deletions src/text-cairo.c
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,40 @@ MeasureString (GpGraphics *graphics, GDIPCONST WCHAR *stringUnicode, int *length
boundingBox->Width = gdip_convgr_unitx (graphics, boundingBox->Width);
boundingBox->Height = gdip_convgr_unity (graphics, boundingBox->Height);
}

switch (AlignVert) {
case StringAlignmentCenter:
if (format->formatFlags & StringFormatFlagsDirectionVertical) {
boundingBox->X += (FrameHeight - MaxY) * 0.5;
} else {
boundingBox->Y += (FrameHeight - MaxY) * 0.5;
}
break;
case StringAlignmentFar:
if (format->formatFlags & StringFormatFlagsDirectionVertical) {
boundingBox->X += (FrameHeight - MaxY);
} else {
boundingBox->Y += (FrameHeight - MaxY);
}
break;
}

switch (AlignHorz) {
case StringAlignmentCenter:
if (format->formatFlags & StringFormatFlagsDirectionVertical) {
boundingBox->Y += (FrameWidth - MaxX) * 0.5;
} else {
boundingBox->X += (FrameWidth - MaxX) * 0.5;
}
break;
case StringAlignmentFar:
if (format->formatFlags & StringFormatFlagsDirectionVertical) {
boundingBox->Y += (FrameWidth - MaxX);
} else {
boundingBox->X += (FrameWidth - MaxX);
}
break;
}
}

if (codepointsFitted) {
Expand All @@ -727,6 +761,44 @@ MeasureString (GpGraphics *graphics, GDIPCONST WCHAR *stringUnicode, int *length
*linesFilled = floor (height / LineHeight);
}

if (AlignHorz != StringAlignmentNear || AlignVert != StringAlignmentNear) {
// Update alignment
int length = 0;
int current_line_length = 0;
for (i = 0; i < StringLen; i++) {
if (i == current_line_length) {
length = StringDetails[i].LineLen;
current_line_length = min(length + i, StringLen);
}

switch (AlignHorz) {
case StringAlignmentNear:
break;
case StringAlignmentCenter:
if ((current_line_length == 1) || (StringDetails [current_line_length - 1].PosX > 0)) {
StringDetails[i].PosX += (FrameWidth - StringDetails [current_line_length - 1].PosX -
StringDetails [current_line_length - 1].Width) / 2;
}
break;
case StringAlignmentFar:
StringDetails[i].PosX += FrameWidth - StringDetails [current_line_length - 1].PosX -
StringDetails [current_line_length - 1].Width;
break;
}

switch (AlignVert) {
case StringAlignmentNear:
break;
case StringAlignmentCenter:
StringDetails[i].PosY += (FrameHeight - MaxY) / 2;
break;
case StringAlignmentFar:
StringDetails[i].PosY += FrameHeight - MaxY;
break;
}
}
}

/* if asked, supply extra data to be reused when drawing the same string */
if (data) {
data->align_horz = AlignHorz;
Expand Down Expand Up @@ -813,55 +885,13 @@ DrawString (GpGraphics *graphics, GDIPCONST WCHAR *stringUnicode, int length, GD

if ((fmt->formatFlags & StringFormatFlagsDirectionVertical)==0) {
CursorX = rc->X + StringDetails[i].PosX;
switch (AlignHorz) {
case StringAlignmentNear:
break;
case StringAlignmentCenter:
/* PosX isn't calculated if the char is out of the bounding box (#79573/#79685) */
if ((current_line_length == 1) || (StringDetails [current_line_length-1].PosX > 0)) {
CursorX += (rc->Width - StringDetails [current_line_length-1].PosX -
StringDetails [current_line_length-1].Width) / 2;
}
/* which means that the line is too long so no centering is required */
break;
case StringAlignmentFar:
CursorX += rc->Width - StringDetails [current_line_length-1].PosX -
StringDetails [current_line_length-1].Width;
break;
}

switch (AlignVert) {
case StringAlignmentNear: CursorY=rc->Y+StringDetails[i].PosY+LineHeight; break;
case StringAlignmentCenter: CursorY=rc->Y+(rc->Height-MaxY)/2+StringDetails[i].PosY+LineHeight; break;
case StringAlignmentFar: CursorY=rc->Y+rc->Height-MaxY+StringDetails[i].PosY+LineHeight; break;
}
CursorY = rc->Y + StringDetails[i].PosY + LineHeight;

gdip_cairo_move_to (graphics, CursorX, CursorY, FALSE, TRUE);
cairo_show_text (graphics->ct, (const char *) String);
} else {
CursorY = rc->Y;
switch (AlignHorz) {
case StringAlignmentNear:
break;
case StringAlignmentCenter:
/* PosX isn't calculated if the char is out of the bounding box (#79573/#79685) */
if ((current_line_length == 1) || (StringDetails [current_line_length-1].PosX > 0)) {
CursorY += (rc->Height - StringDetails[current_line_length-1].PosX -
StringDetails [current_line_length-1].Width) / 2;
}
/* which means that the line is too long so no centering is required */
break;
case StringAlignmentFar:
CursorY += rc->Height - StringDetails[current_line_length-1].PosX -
StringDetails [current_line_length-1].Width;
break;
}

switch (AlignVert) {
case StringAlignmentNear: CursorX=rc->X + StringDetails[i].PosX+StringDetails[i].PosY; break;
case StringAlignmentCenter: CursorX=rc->X + StringDetails[i].PosX+(rc->Width-MaxY)/2+StringDetails[i].PosY; break;
case StringAlignmentFar: CursorX=rc->X + StringDetails[i].PosX+rc->Width-MaxY+StringDetails[i].PosY; break;
}
CursorY = rc->Y + StringDetails[i].PosX;
CursorX = rc->X + StringDetails[i].PosY;

/* Rotate text for vertical drawing */
cairo_save (graphics->ct);
Expand Down Expand Up @@ -915,48 +945,23 @@ DrawString (GpGraphics *graphics, GDIPCONST WCHAR *stringUnicode, int length, GD
if (fmt->hotkeyPrefix==HotkeyPrefixShow && data->has_hotkeys) {
GpStringDetailStruct *CurrentDetail = StringDetails;
for (i=0; i<StringLen; i++) {
if (CurrentDetail->Flags & STRING_DETAIL_LINESTART) {
if (CurrentDetail->Flags & STRING_DETAIL_HOTKEY) {
if ((fmt->formatFlags & StringFormatFlagsDirectionVertical)==0) {
switch (AlignHorz) {
case StringAlignmentNear: CursorX=rc->X; break;
case StringAlignmentCenter: CursorX=rc->X+(rc->Width-StringDetails[i+StringDetails[i].LineLen-1].PosX-StringDetails[i+StringDetails[i].LineLen-1].Width)/2; break;
case StringAlignmentFar: CursorX=rc->X+rc->Width-StringDetails[i+StringDetails[i].LineLen-1].PosX-StringDetails[i+StringDetails[i].LineLen-1].Width; break;
}

switch (AlignVert) {
case StringAlignmentNear: CursorY=rc->Y+StringDetails[i].PosY+LineHeight; break;
case StringAlignmentCenter: CursorY=rc->Y+(rc->Height-MaxY)/2+StringDetails[i].PosY+LineHeight; break;
case StringAlignmentFar: CursorY=rc->Y+rc->Height-MaxY+StringDetails[i].PosY+LineHeight; break;
}
CursorX = rc->X + StringDetails[i].PosX;
CursorY = rc->Y + StringDetails[i].PosY + LineHeight;
} else {
switch (AlignHorz) {
case StringAlignmentNear: CursorY=rc->Y; break;
case StringAlignmentCenter: CursorY=rc->Y+(rc->Height-StringDetails[i+StringDetails[i].LineLen-1].PosX-StringDetails[i+StringDetails[i].LineLen-1].Width)/2; break;
case StringAlignmentFar: CursorY=rc->Y+rc->Height-StringDetails[i+StringDetails[i].LineLen-1].PosX-StringDetails[i+StringDetails[i].LineLen-1].Width; break;
}

switch (AlignVert) {
case StringAlignmentNear: CursorX=rc->X+StringDetails[i].PosY; break;
case StringAlignmentCenter: CursorX=rc->X+(rc->Width-MaxY)/2+StringDetails[i].PosY; break;
case StringAlignmentFar: CursorX=rc->X+rc->Width-MaxY+StringDetails[i].PosY; break;
}
CursorY = rc->Y + StringDetails[i].PosX;
CursorX = rc->X + StringDetails[i].PosY;
}
}

if (CurrentDetail->Flags & STRING_DETAIL_HOTKEY) {
if ((fmt->formatFlags & StringFormatFlagsDirectionVertical)==0) {
CursorX+=CurrentDetail->PosX;
cairo_set_line_width(graphics->ct, 1);

gdip_cairo_move_to (graphics, (int)(CursorX), (int)(CursorY+FontExtent.descent/2), FALSE, TRUE);
gdip_cairo_line_to (graphics, (int)(CursorX+CurrentDetail->Width), (int)(CursorY+FontExtent.descent/2), FALSE, TRUE);
gdip_cairo_move_to (graphics, (int)(CursorX), (int)(CursorY+FontExtent.descent), FALSE, TRUE);
gdip_cairo_line_to (graphics, (int)(CursorX+CurrentDetail->Width), (int)(CursorY+FontExtent.descent), FALSE, TRUE);
cairo_stroke (graphics->ct);
CursorX-=CurrentDetail->PosX;
} else {
CursorY+=CurrentDetail->PosX;
gdip_cairo_move_to (graphics, (int)(CursorX-FontExtent.descent/2), (int)(CursorY), FALSE, TRUE);
gdip_cairo_line_to (graphics, (int)(CursorX-FontExtent.descent/2), (int)(CursorY+CurrentDetail->Width), FALSE, TRUE);
CursorY-=CurrentDetail->PosX;
gdip_cairo_move_to (graphics, (int)(CursorX-FontExtent.descent), (int)(CursorY), FALSE, TRUE);
gdip_cairo_line_to (graphics, (int)(CursorX-FontExtent.descent), (int)(CursorY+CurrentDetail->Width), FALSE, TRUE);
}
}
CurrentDetail++;
Expand Down Expand Up @@ -1164,13 +1169,13 @@ cairo_MeasureCharacterRanges (GpGraphics *graphics, GDIPCONST WCHAR *stringUnico
continue;

if (format->formatFlags & StringFormatFlagsDirectionVertical) {
charRect.X = StringDetails [j].PosY;
charRect.Y = StringDetails [j].PosX;
charRect.X = layoutRect->X + StringDetails [j].PosY;
charRect.Y = layoutRect->Y + StringDetails [j].PosX;
charRect.Width = lineHeight;
charRect.Height = StringDetails [j].Width;
} else {
charRect.X = StringDetails [j].PosX;
charRect.Y = StringDetails [j].PosY;
charRect.X = layoutRect->X + StringDetails [j].PosX;
charRect.Y = layoutRect->Y + StringDetails [j].PosY;
charRect.Width = StringDetails [j].Width;
charRect.Height = lineHeight;
}
Expand Down
17 changes: 13 additions & 4 deletions src/text-pango.c
Original file line number Diff line number Diff line change
Expand Up @@ -714,10 +714,17 @@ pango_MeasureCharacterRanges (GpGraphics *graphics, GDIPCONST WCHAR *stringUnico
GpRectF charRect;

pango_layout_index_to_pos (layout, idxUtf8, &box);
charRect.X = (float)box.x / PANGO_SCALE + box_offset.X;
charRect.Y = (float)box.y / PANGO_SCALE + box_offset.Y;
charRect.Width = (float)box.width / PANGO_SCALE;
charRect.Height = (float)box.height / PANGO_SCALE;
if (format->formatFlags & StringFormatFlagsDirectionVertical) {
charRect.X = (float)box.y / PANGO_SCALE;
charRect.Y = (float)box.x / PANGO_SCALE;
charRect.Width = (float)box.height / PANGO_SCALE;
charRect.Height = (float)box.width / PANGO_SCALE;
} else {
charRect.X = (float)box.x / PANGO_SCALE;
charRect.Y = (float)box.y / PANGO_SCALE;
charRect.Width = (float)box.width / PANGO_SCALE;
charRect.Height = (float)box.height / PANGO_SCALE;
}
/* Normalize values (width/height can be negative) */
if (charRect.Width < 0) {
charRect.Width = -charRect.Width;
Expand All @@ -727,6 +734,8 @@ pango_MeasureCharacterRanges (GpGraphics *graphics, GDIPCONST WCHAR *stringUnico
charRect.Height = -charRect.Height;
charRect.Y -= charRect.Height;
}
charRect.X += box_offset.X + layoutRect->X;
charRect.Y += box_offset.Y + layoutRect->Y;
// g_warning ("[%d] [%d : %d-%d] %c [x %g y %g w %g h %g]", i, j, start, end, (char)stringUnicode[j], charRect.X, charRect.Y, charRect.Width, charRect.Height);
status = GdipCombineRegionRect (regions [i], &charRect, CombineModeUnion);
if (status != Ok)
Expand Down
22 changes: 19 additions & 3 deletions tests/testtext.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ static void test_measure_string(void)
GdipDisposeImage (image);
}

#endif

static void test_measure_string_alignment(void)
{
GpStringFormat *format;
Expand All @@ -117,8 +119,10 @@ static void test_measure_string_alignment(void)
GpFont *font;
GpStatus status;
GpRectF rect, bounds;
GpRegion *region;
const WCHAR teststring1[] = { 'M', 0 };
INT i;
static const CharacterRange character_range = { 0, 1 };
static const struct test_data
{
INT flags;
Expand Down Expand Up @@ -167,12 +171,16 @@ static void test_measure_string_alignment(void)
expect (Ok, status);
status = GdipCreateFont (family, 10, FontStyleRegular, UnitPixel, &font);
expect (Ok, status);
status = GdipCreateRegion (&region);
expect (Ok, status);
status = GdipCreateBitmapFromScan0 (400, 400, 0, PixelFormat32bppRGB, NULL, (GpBitmap **) &image);
expect (Ok, status);
status = GdipGetImageGraphicsContext (image, &graphics);
expect (Ok, status);
ok (graphics != NULL, "Expected graphics to be initialized\n");

GdipSetStringFormatMeasurableCharacterRanges (format, 1, &character_range);

for (i = 0; i < sizeof(td) / sizeof(td[0]); i++) {
GdipSetStringFormatFlags (format, td[i].flags);
GdipSetStringFormatAlign (format, td[i].alignment);
Expand All @@ -189,26 +197,34 @@ static void test_measure_string_alignment(void)
expectf_ (td[i].y_y0 + td[i].y_yy * bounds.Height + 10.0, bounds.Y, 0.6);
expectf_ (td[i].right_x0 + td[i].right_xx * bounds.Width + 5.0, bounds.X + bounds.Width, 0.6);
expectf_ (td[i].bottom_y0 + td[i].bottom_yy * bounds.Height + 10.0, bounds.Y + bounds.Height, 0.6);

status = GdipMeasureCharacterRanges (graphics, teststring1, 1, font, &rect, format, 1, &region);
expect (Ok, status);
status = GdipGetRegionBounds (region, graphics, &bounds);
expect (Ok, status);
expectf_ (td[i].x_x0 + td[i].x_xx * bounds.Width + 5.0, bounds.X, 3.0);
expectf_ (td[i].y_y0 + td[i].y_yy * bounds.Height + 10.0, bounds.Y, 3.0);
expectf_ (td[i].right_x0 + td[i].right_xx * bounds.Width + 5.0, bounds.X + bounds.Width, 3.0);
expectf_ (td[i].bottom_y0 + td[i].bottom_yy * bounds.Height + 10.0, bounds.Y + bounds.Height, 3.0);
}

GdipDeleteGraphics (graphics);
GdipDeleteFont (font);
GdipDeleteFontFamily (family);
GdipDeleteStringFormat (format);
GdipDisposeImage (image);
GdipDeleteRegion (region);
}

#endif

int
main (int argc, char**argv)
{
STARTUP;

#if defined(USE_PANGO_RENDERING) || defined(USE_WINDOWS_GDIPLUS)
test_measure_string ();
test_measure_string_alignment ();
#endif
test_measure_string_alignment ();

SHUTDOWN;
return 0;
Expand Down