summaryrefslogtreecommitdiff
path: root/ext/gd/libgd
diff options
context:
space:
mode:
authorMark Plomer <mail@mark-plomer.de>2016-04-03 11:52:59 +0200
committerMark Plomer <mail@mark-plomer.de>2016-04-03 12:11:26 +0200
commitf5f94d9c089cb670e9c119fff4102af1ffc7fbe5 (patch)
treebee5ea5bc7992aba6c3657f3a4fef67165c97baa /ext/gd/libgd
parent9f25f736ed50a2dc94aeff4f289c1a5e26fc6a40 (diff)
downloadphp-git-f5f94d9c089cb670e9c119fff4102af1ffc7fbe5.tar.gz
fix left-shifted/misaligned bounding-box + wrong kerning in imagettfbbox/imageftbbox
- load glyph with FT_LOAD_IGNORE_TRANSFORM for bbox as final bbox is rotated at once later (fixes "double-rotation" per glyph for calculating bbox) - reload the rotated glyph for painting after that (only if angle != 0) - rotate the original bbox at 0,0 and do not throw away xMin/yMin (drawing-rotation is also based at "origin" point - including the bearingX, see http://www.freetype.org/freetype2/docs/glyphs/glyphs-3.html#section-3) - this fixes the "left-shift"-problem also when angle = 0 - removed "xb/yb" and use "x/y" directly for offsetting brect (no need for adding "x1/y1" and substracting "yd" later) - removed therefore unused "yd" helper var which seems tried to fix parts of the original problems - initialize x/y with 0 instead of -1 in php_imagettftext_common() to make image*text() and image*bbox() results identical (there was a -1px shift in image*bbox() before) - fixed gdroundupdown() for negative numbers (-256 / 64 gives -5 instead of -4 before) - rotate kerning-delta by given angle (fixes completely wrong kerning and therefore wrong bounding box if angle != 0) - changed 3 tests and added a new one to test for the new (better) coordinates
Diffstat (limited to 'ext/gd/libgd')
-rw-r--r--ext/gd/libgd/gdft.c127
1 files changed, 66 insertions, 61 deletions
diff --git a/ext/gd/libgd/gdft.c b/ext/gd/libgd/gdft.c
index 763efcf68c..b74c4938ea 100644
--- a/ext/gd/libgd/gdft.c
+++ b/ext/gd/libgd/gdft.c
@@ -748,9 +748,9 @@ static char * gdft_draw_bitmap (gdCache_head_t *tc_cache, gdImage * im, int fg,
}
static int
-gdroundupdown (FT_F26Dot6 v1, int updown)
+gdroundupdown (FT_F26Dot6 v1, int roundup)
{
- return (!updown) ? (v1 < 0 ? ((v1 - 63) >> 6) : v1 >> 6) : (v1 > 0 ? ((v1 + 63) >> 6) : v1 >> 6);
+ return (!roundup) ? v1 >> 6 : (v1 + 63) >> 6;
}
void gdFontCacheShutdown()
@@ -820,8 +820,6 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
double cos_a = cos (angle);
int len, i = 0, ch;
int x1 = 0, y1 = 0;
- int xb = x, yb = y;
- int yd = 0;
font_t *font;
fontkey_t fontkey;
char *next;
@@ -982,9 +980,6 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
penf.y = (penf.y - 32) & -64; /* round to next pixel row */
x1 = (int)(- penf.y * sin_a + 32) / 64;
y1 = (int)(- penf.y * cos_a + 32) / 64;
- xb = x + x1;
- yb = y + y1;
- yd = 0;
pen.x = pen.y = 0;
previous = 0; /* clear kerning flag */
continue;
@@ -1074,31 +1069,32 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
/* retrieve kerning distance and move pen position */
if (use_kerning && previous && glyph_index) {
FT_Get_Kerning(face, previous, glyph_index, ft_kerning_default, &delta);
- pen.x += delta.x;
+ pen.x += (int)(delta.x * cos_a);
+ pen.y -= (int)(delta.x * sin_a);
penf.x += delta.x;
}
- /* load glyph image into the slot (erase previous one) */
- if (FT_Load_Glyph(face, glyph_index, render_mode)) {
- if (tmpstr) {
- gdFree(tmpstr);
+ if (brect) { /* only if need brect */
+ /* load glyph image into the slot (erase previous one) */
+ if (FT_Load_Glyph(face, glyph_index, render_mode | FT_LOAD_IGNORE_TRANSFORM)) {
+ if (tmpstr) {
+ gdFree(tmpstr);
+ }
+ gdCacheDelete(tc_cache);
+ gdMutexUnlock(gdFontCacheMutex);
+ return "Problem loading glyph";
}
- gdCacheDelete(tc_cache);
- gdMutexUnlock(gdFontCacheMutex);
- return "Problem loading glyph";
- }
- /* transform glyph image */
- if (FT_Get_Glyph(slot, &image)) {
- if (tmpstr) {
- gdFree(tmpstr);
+ /* transform glyph image */
+ if (FT_Get_Glyph(slot, &image)) {
+ if (tmpstr) {
+ gdFree(tmpstr);
+ }
+ gdCacheDelete(tc_cache);
+ gdMutexUnlock(gdFontCacheMutex);
+ return "Problem loading glyph";
}
- gdCacheDelete(tc_cache);
- gdMutexUnlock(gdFontCacheMutex);
- return "Problem loading glyph";
- }
- if (brect) { /* only if need brect */
FT_Glyph_Get_CBox(image, ft_glyph_bbox_gridfit, &glyph_bbox);
glyph_bbox.xMin += penf.x;
glyph_bbox.yMin += penf.y;
@@ -1108,17 +1104,11 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
glyph_bbox.xMax += slot->metrics.horiAdvance;
}
if (!i) { /* if first character, init BB corner values */
- yd = slot->metrics.height - slot->metrics.horiBearingY;
bbox.xMin = glyph_bbox.xMin;
bbox.yMin = glyph_bbox.yMin;
bbox.xMax = glyph_bbox.xMax;
bbox.yMax = glyph_bbox.yMax;
} else {
- FT_Pos desc;
-
- if ( (desc = (slot->metrics.height - slot->metrics.horiBearingY)) > yd) {
- yd = desc;
- }
if (bbox.xMin > glyph_bbox.xMin) {
bbox.xMin = glyph_bbox.xMin;
}
@@ -1135,7 +1125,35 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
i++;
}
+ /* increment (unrotated) pen position */
+ penf.x += slot->metrics.horiAdvance;
+
if (render) {
+ if (!brect || angle != 0) {
+ /* reload the rotated glyph (for bbox we needed FT_LOAD_IGNORE_TRANSFORM - bbox is rotated later) */
+ FT_Done_Glyph(image);
+
+ /* load glyph image into the slot (erase previous one) */
+ if (FT_Load_Glyph(face, glyph_index, render_mode)) {
+ if (tmpstr) {
+ gdFree(tmpstr);
+ }
+ gdCacheDelete(tc_cache);
+ gdMutexUnlock(gdFontCacheMutex);
+ return "Problem loading glyph";
+ }
+
+ /* transform glyph image */
+ if (FT_Get_Glyph(slot, &image)) {
+ if (tmpstr) {
+ gdFree(tmpstr);
+ }
+ gdCacheDelete(tc_cache);
+ gdMutexUnlock(gdFontCacheMutex);
+ return "Problem loading glyph";
+ }
+ }
+
if (image->format != ft_glyph_format_bitmap && FT_Glyph_To_Bitmap(&image, ft_render_mode_normal, 0, 1)) {
FT_Done_Glyph(image);
if (tmpstr) {
@@ -1158,8 +1176,6 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
pen.x += image->advance.x >> 10;
pen.y -= image->advance.y >> 10;
- penf.x += slot->metrics.horiAdvance;
-
FT_Done_Glyph(image);
}
@@ -1168,36 +1184,25 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
double d1 = sin (angle + 0.78539816339744830962);
double d2 = sin (angle - 0.78539816339744830962);
- /* make the center of rotation at (0, 0) */
- FT_BBox normbox;
-
- normbox.xMin = 0;
- normbox.yMin = 0;
- normbox.xMax = bbox.xMax - bbox.xMin;
- normbox.yMax = bbox.yMax - bbox.yMin;
-
- brect[0] = brect[2] = brect[4] = brect[6] = (int) (yd * sin_a);
- brect[1] = brect[3] = brect[5] = brect[7] = (int)(- yd * cos_a);
-
- /* rotate bounding rectangle */
- brect[0] += (int) (normbox.xMin * cos_a - normbox.yMin * sin_a);
- brect[1] += (int) (normbox.xMin * sin_a + normbox.yMin * cos_a);
- brect[2] += (int) (normbox.xMax * cos_a - normbox.yMin * sin_a);
- brect[3] += (int) (normbox.xMax * sin_a + normbox.yMin * cos_a);
- brect[4] += (int) (normbox.xMax * cos_a - normbox.yMax * sin_a);
- brect[5] += (int) (normbox.xMax * sin_a + normbox.yMax * cos_a);
- brect[6] += (int) (normbox.xMin * cos_a - normbox.yMax * sin_a);
- brect[7] += (int) (normbox.xMin * sin_a + normbox.yMax * cos_a);
+ /* rotate bounding rectangle (at 0, 0) */
+ brect[0] = (int) (bbox.xMin * cos_a - bbox.yMin * sin_a);
+ brect[1] = (int) (bbox.xMin * sin_a + bbox.yMin * cos_a);
+ brect[2] = (int) (bbox.xMax * cos_a - bbox.yMin * sin_a);
+ brect[3] = (int) (bbox.xMax * sin_a + bbox.yMin * cos_a);
+ brect[4] = (int) (bbox.xMax * cos_a - bbox.yMax * sin_a);
+ brect[5] = (int) (bbox.xMax * sin_a + bbox.yMax * cos_a);
+ brect[6] = (int) (bbox.xMin * cos_a - bbox.yMax * sin_a);
+ brect[7] = (int) (bbox.xMin * sin_a + bbox.yMax * cos_a);
/* scale, round and offset brect */
- brect[0] = xb + gdroundupdown(brect[0], d2 > 0);
- brect[1] = yb - gdroundupdown(brect[1], d1 < 0);
- brect[2] = xb + gdroundupdown(brect[2], d1 > 0);
- brect[3] = yb - gdroundupdown(brect[3], d2 > 0);
- brect[4] = xb + gdroundupdown(brect[4], d2 < 0);
- brect[5] = yb - gdroundupdown(brect[5], d1 > 0);
- brect[6] = xb + gdroundupdown(brect[6], d1 < 0);
- brect[7] = yb - gdroundupdown(brect[7], d2 < 0);
+ brect[0] = x + gdroundupdown(brect[0], d2 > 0);
+ brect[1] = y - gdroundupdown(brect[1], d1 < 0);
+ brect[2] = x + gdroundupdown(brect[2], d1 > 0);
+ brect[3] = y - gdroundupdown(brect[3], d2 > 0);
+ brect[4] = x + gdroundupdown(brect[4], d2 < 0);
+ brect[5] = y - gdroundupdown(brect[5], d1 > 0);
+ brect[6] = x + gdroundupdown(brect[6], d1 < 0);
+ brect[7] = y - gdroundupdown(brect[7], d2 < 0);
}
if (tmpstr) {