Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit 14a74f2

Browse files
committed
[[ Bug 18669 ]] Fix rotated text rendering on Linux
Fix calculation of text bounds in device coordinates. Fix production of PangoMatrix from MCGAffineTransform.
1 parent 690a446 commit 14a74f2

File tree

1 file changed

+48
-35
lines changed

1 file changed

+48
-35
lines changed

libgraphics/src/lnxtext.cpp

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,25 @@ static inline MCGRectangle MCGRectangleFromPangoRectangle(const PangoRectangle &
4444
return MCGRectangleMake(p_rect.x / (MCGFloat)PANGO_SCALE, p_rect.y / (MCGFloat)PANGO_SCALE, p_rect.width / (MCGFloat)PANGO_SCALE, p_rect.height / (MCGFloat)PANGO_SCALE);
4545
}
4646

47+
static inline PangoMatrix MCGAffineTransformToPangoMatrix(const MCGAffineTransform &p_transform)
48+
{
49+
PangoMatrix t_matrix;
50+
t_matrix . xx = p_transform . a;
51+
t_matrix . yx = p_transform . b;
52+
t_matrix . xy = p_transform . c;
53+
t_matrix . yy = p_transform . d;
54+
t_matrix . x0 = p_transform . tx;
55+
t_matrix . y0 = p_transform . ty;
56+
return t_matrix;
57+
}
58+
4759
////////////////////////////////////////////////////////////////////////////////
4860

4961
static PangoFontMap *s_font_map = NULL;
5062
static PangoContext *s_pango = NULL;
5163
static PangoLayout *s_layout = NULL;
5264

53-
static bool lnx_pango_objects_intialize()
65+
static bool lnx_pango_objects_initialize()
5466
{
5567
bool t_success;
5668
t_success = true;
@@ -91,7 +103,7 @@ static bool lnx_pango_initialize(void)
91103

92104

93105
if (t_success)
94-
t_success = lnx_pango_objects_intialize();
106+
t_success = lnx_pango_objects_initialize();
95107

96108
return t_success;
97109
}
@@ -141,25 +153,19 @@ void MCGContextDrawPlatformText(MCGContextRef self, const unichar_t *p_text, uin
141153
t_success = MCCStringFromUnicodeSubstring(p_text, p_length / 2, t_text);
142154

143155
MCGAffineTransform t_transform;
144-
MCGPoint t_device_location;
156+
t_transform = MCGContextGetDeviceTransform(self);
157+
145158
PangoLayoutLine *t_line;
146159
t_line = nil;
147160
if (t_success)
148161
{
149-
t_transform = MCGContextGetDeviceTransform(self);
150-
t_device_location = MCGPointApplyAffineTransform(p_location, t_transform);
151-
t_transform . tx = modff(t_device_location . x, &t_device_location . x);
152-
t_transform . ty = modff(t_device_location . y, &t_device_location . y);
153-
154-
PangoMatrix t_ptransform;
155-
t_ptransform . xx = t_transform . a;
156-
t_ptransform . xy = t_transform . b;
157-
t_ptransform . yx = t_transform . c;
158-
t_ptransform . yy = t_transform . d;
159-
t_ptransform . x0 = t_transform . tx;
160-
t_ptransform . y0 = t_transform . ty;
162+
// The transform needs to be applied before setting the text + font,
163+
// otherwise the glyph orientation will be incorrectly set from the
164+
// previous transform.
165+
PangoMatrix t_ptransform;
166+
t_ptransform = MCGAffineTransformToPangoMatrix(t_transform);
161167
pango_context_set_matrix(s_pango, &t_ptransform);
162-
168+
163169
pango_layout_set_font_description(s_layout, (PangoFontDescription *) p_font . fid);
164170
pango_layout_set_text(s_layout, t_text, -1);
165171
MCCStringFree(t_text);
@@ -172,7 +178,7 @@ void MCGContextDrawPlatformText(MCGContextRef self, const unichar_t *p_text, uin
172178
t_success = t_line != nil;
173179
}
174180

175-
MCGIntRectangle t_text_bounds, t_clipped_bounds;
181+
MCGIntegerRectangle t_bitmap_bounds;
176182
if (t_success)
177183
{
178184
PangoRectangle t_pbounds;
@@ -181,45 +187,52 @@ void MCGContextDrawPlatformText(MCGContextRef self, const unichar_t *p_text, uin
181187
MCGRectangle t_float_text_bounds;
182188
t_float_text_bounds = MCGRectangleFromPangoRectangle(t_pbounds);
183189

190+
// Apply translation to put target location at the origin
191+
t_transform = MCGAffineTransformPostTranslate(t_transform, p_location.x, p_location.y);
192+
193+
MCGRectangle t_device_text_bounds;
194+
t_device_text_bounds = MCGRectangleApplyAffineTransform(t_float_text_bounds, t_transform);
195+
184196
MCGRectangle t_device_clip;
185197
t_device_clip = MCGContextGetDeviceClipBounds(self);
186-
t_device_clip . origin . x -= t_device_location . x;
187-
t_device_clip . origin . y -= t_device_location . y;
188-
189-
MCGRectangle t_float_clipped_bounds;
190-
t_float_clipped_bounds = MCGRectangleIntersection(t_float_text_bounds, t_device_clip);
191-
192-
t_text_bounds = MCGRectangleIntegerBounds(t_float_text_bounds);
193-
t_clipped_bounds = MCGRectangleIntegerBounds(t_float_clipped_bounds);
198+
199+
t_bitmap_bounds = MCGRectangleGetBounds(MCGRectangleIntersection(t_device_text_bounds, t_device_clip));
194200

195-
if (t_clipped_bounds . width == 0 || t_clipped_bounds . height == 0)
201+
if (t_bitmap_bounds.size.width == 0 || t_bitmap_bounds.size.height == 0)
196202
return;
197203
}
198204

199205
void *t_data;
200206
t_data = nil;
201207
if (t_success)
202-
t_success = MCMemoryNew(t_clipped_bounds . width * t_clipped_bounds . height, t_data);
208+
t_success = MCMemoryNew(t_bitmap_bounds.size.width * t_bitmap_bounds.size.height, t_data);
203209

204210
if (t_success)
205211
{
206212
FT_Bitmap t_ftbitmap;
207-
t_ftbitmap . rows = t_clipped_bounds . height;
208-
t_ftbitmap . width = t_clipped_bounds . width;
209-
t_ftbitmap . pitch = t_clipped_bounds . width;
213+
t_ftbitmap . rows = t_bitmap_bounds.size.height;
214+
t_ftbitmap . width = t_bitmap_bounds.size.width;
215+
t_ftbitmap . pitch = t_bitmap_bounds.size.width;
210216
t_ftbitmap . buffer = (unsigned char*) t_data;
211217
t_ftbitmap . num_grays = 256;
212218
t_ftbitmap . pixel_mode = FT_PIXEL_MODE_GRAY;
213219
t_ftbitmap . palette_mode = 0;
214220
t_ftbitmap . palette = nil;
221+
222+
// Apply translation to offset drawing into the bitmap
223+
t_transform = MCGAffineTransformPreTranslate(t_transform, -t_bitmap_bounds.origin.x, -t_bitmap_bounds.origin.y);
224+
225+
PangoMatrix t_ptransform;
226+
t_ptransform = MCGAffineTransformToPangoMatrix(t_transform);
227+
pango_context_set_matrix(s_pango, &t_ptransform);
215228

216-
pango_ft2_render_layout_line(&t_ftbitmap, t_line, -(t_clipped_bounds . x - t_text_bounds . x), -(t_clipped_bounds . y - t_text_bounds . y) - t_text_bounds . y);
229+
pango_ft2_render_layout_line(&t_ftbitmap, t_line, 0, 0);
217230

218231
// The paint containing the fill settings
219232
SkPaint t_paint;
220233
if (MCGContextSetupFill(self, t_paint))
221234
{
222-
SkImageInfo t_info = SkImageInfo::MakeA8(t_clipped_bounds.width, t_clipped_bounds.height);
235+
SkImageInfo t_info = SkImageInfo::MakeA8(t_bitmap_bounds.size.width, t_bitmap_bounds.size.height);
223236

224237
SkBitmap t_bitmap;
225238
t_bitmap.setInfo(t_info);
@@ -228,8 +241,8 @@ void MCGContextDrawPlatformText(MCGContextRef self, const unichar_t *p_text, uin
228241
self->layer->canvas->save();
229242
self->layer->canvas->resetMatrix();
230243
self->layer->canvas->drawBitmap(t_bitmap,
231-
t_clipped_bounds.x + t_device_location.x,
232-
t_clipped_bounds.y + t_device_location.y,
244+
t_bitmap_bounds.origin.x,
245+
t_bitmap_bounds.origin.y,
233246
&t_paint);
234247
self->layer->canvas->restore();
235248
}
@@ -284,7 +297,7 @@ bool MCGContextMeasurePlatformTextImageBounds(MCGContextRef self, const unichar_
284297
t_success = true;
285298

286299
if (t_success)
287-
t_success = lnx_pango_objects_intialize();
300+
t_success = lnx_pango_objects_initialize();
288301

289302
char *t_text;
290303
t_text = nil;

0 commit comments

Comments
 (0)