diff --git a/src/text-cairo.c b/src/text-cairo.c index f35374aa7..2d0c27ba8 100644 --- a/src/text-cairo.c +++ b/src/text-cairo.c @@ -707,11 +707,27 @@ MeasureString (GpGraphics *graphics, GDIPCONST WCHAR *stringUnicode, int *length boundingBox->Width = MaxX; boundingBox->Height = MaxY; } - if ((rc->Width > 0) && (boundingBox->Width > rc->Width)) { - boundingBox->Width = rc->Width; + if (rc->Width > 0) { + if (boundingBox->Width > rc->Width) { + boundingBox->Width = rc->Width; + } else { + if (format->formatFlags & StringFormatFlagsDirectionVertical) { + boundingBox->Y += (rc->Width - boundingBox->Width) / 2; + } else { + boundingBox->X += (rc->Width - boundingBox->Width) / 2; + } + } } - if ((rc->Height > 0) && (boundingBox->Height > rc->Height)) { - boundingBox->Height = rc->Height; + if (rc->Height > 0) { + if (boundingBox->Height > rc->Height) { + boundingBox->Height = rc->Height; + } else { + if (format->formatFlags & StringFormatFlagsDirectionVertical) { + boundingBox->X += (rc->Height - boundingBox->Height) / 2; + } else { + boundingBox->Y += (rc->Height - boundingBox->Height) / 2; + } + } } /* avoid conversion computations if possible */ @@ -776,6 +792,72 @@ MeasureString (GpGraphics *graphics, GDIPCONST WCHAR *stringUnicode, int *length double height = (boundingBox) ? boundingBox->Height : min (MaxY, rc->Height); *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); + } + + if ((format->formatFlags & StringFormatFlagsDirectionVertical) == 0) { + switch (AlignHorz) { + case StringAlignmentNear: + break; + case StringAlignmentCenter: + if ((current_line_length == 1) || (StringDetails [current_line_length - 1].PosX > 0)) { + StringDetails[i].PosX += (rc->Width - StringDetails [current_line_length - 1].PosX - + StringDetails [current_line_length - 1].Width) / 2; + } + break; + case StringAlignmentFar: + StringDetails[i].PosX += rc->Width - StringDetails [current_line_length - 1].PosX - + StringDetails [current_line_length - 1].Width; + break; + } + + switch (AlignVert) { + case StringAlignmentNear: + break; + case StringAlignmentCenter: + StringDetails[i].PosY += (rc->Height - MaxY) / 2; + break; + case StringAlignmentFar: + StringDetails[i].PosY += rc->Height - MaxY; + break; + } + } else { + switch (AlignVert) { + case StringAlignmentNear: + break; + case StringAlignmentCenter: + if ((current_line_length == 1) || (StringDetails [current_line_length - 1].PosX > 0)) { + StringDetails[i].PosX += (rc->Height - StringDetails [current_line_length - 1].PosX - + StringDetails [current_line_length - 1].Width) / 2; + } + break; + case StringAlignmentFar: + StringDetails[i].PosX += rc->Height - StringDetails [current_line_length - 1].PosX - + StringDetails [current_line_length - 1].Width; + break; + } + + switch (AlignHorz) { + case StringAlignmentNear: + break; + case StringAlignmentCenter: + StringDetails[i].PosY += (rc->Width - MaxY) / 2; + break; + case StringAlignmentFar: + StringDetails[i].PosY += rc->Width - MaxY; + break; + } + } + } + } if (AlignHorz != StringAlignmentNear || AlignVert != StringAlignmentNear) { // Update alignment @@ -1100,10 +1182,15 @@ cairo_MeasureCharacterRanges (GpGraphics *graphics, GDIPCONST WCHAR *stringUnico RectF charRect; RectF rc_coords, *layoutRect = &rc_coords; BOOL optimize_convert; + int *index_matching; WCHAR *CleanString; GpDrawTextData data; /* avoid recomputation of stuff done while measuring */ int StringLen = length; + index_matching = (int *) malloc (sizeof (int) * length); + if (!index_matching) + return OutOfMemory; + GpStatus status = AllocStringData (&CleanString, &StringDetails, length); if (status != Ok) return status; @@ -1143,7 +1230,34 @@ cairo_MeasureCharacterRanges (GpGraphics *graphics, GDIPCONST WCHAR *stringUnico if (status != Ok) goto cleanup; - lineHeight = data.line_height + data.descent; + lineHeight = data.line_height; //+ data.descent; + + j = 0; // index in StringDetails + for (i = 0; i < length; i++) { + switch (stringUnicode[i]) { + case '\r': /* CR */ + case '\t': /* Tab */ + case '\n': /* LF */ + { + index_matching[i] = -1; // not present in StringDetails + break; + } + + case '&': + { + if (format->hotkeyPrefix != HotkeyPrefixNone && (StringDetails[j].Flags & STRING_DETAIL_HOTKEY)) { + // Not present, because it is a hotkey + index_matching[i] = -1; + break; + } // else fall through to default + } + + default: + { + index_matching[i] = j++; + } + } + } /* Create a region for every char range */ for (i = 0; i < format->charRangeCount; i++) { @@ -1170,26 +1284,18 @@ cairo_MeasureCharacterRanges (GpGraphics *graphics, GDIPCONST WCHAR *stringUnico /* calculate the regions */ for (j = start; j < end; j++) { - - /* the prefix char (&) always count - even if we are not actually print it as a char */ - if ((StringDetails[j].Flags & STRING_DETAIL_HOTKEY) && (format->hotkeyPrefix != HotkeyPrefixNone)) { - end--; /* '&' count as invisible char */ - continue; - } - - /* workaround the fact that current implementation thinks LF is on the next line */ - if ((j == end - 1) && (StringDetails[j].Flags & STRING_DETAIL_LF)) + if (index_matching[j] == -1) continue; if (format->formatFlags & StringFormatFlagsDirectionVertical) { - charRect.X = layoutRect->X + StringDetails [j].PosY; - charRect.Y = layoutRect->Y + StringDetails [j].PosX; + charRect.X = layoutRect->X + StringDetails [index_matching[j]].PosY; + charRect.Y = layoutRect->Y + StringDetails [index_matching[j]].PosX + data.descent; charRect.Width = lineHeight; - charRect.Height = StringDetails [j].Width; + charRect.Height = StringDetails [index_matching[j]].Width; } else { - charRect.X = layoutRect->X + StringDetails [j].PosX; - charRect.Y = layoutRect->Y + StringDetails [j].PosY; - charRect.Width = StringDetails [j].Width; + charRect.X = layoutRect->X + StringDetails [index_matching[j]].PosX; + charRect.Y = layoutRect->Y + StringDetails [index_matching[j]].PosY + data.descent; + charRect.Width = StringDetails [index_matching[j]].Width; charRect.Height = lineHeight; } @@ -1210,6 +1316,7 @@ cairo_MeasureCharacterRanges (GpGraphics *graphics, GDIPCONST WCHAR *stringUnico cleanup: /* Cleanup */ + free (index_matching); GdipFree (CleanString); GdipFree (StringDetails);