diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2013-10-16 22:39:54 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2013-10-16 22:54:09 +0100 |
commit | ec0866e86d365ae3fd9790b1b263d49fc4981220 (patch) | |
tree | 71fd0f782e6935148a4fb0f0b050a7029e84f539 /src/sna/sna_glyphs.c | |
parent | 09121a61b319ce365bfc6f96fb34c52d6eafffdf (diff) |
sna/glyphs: Fix computation of extents for long strings
And make sure we consider such overflowing strings for correct clipping
against Windows.
To offset the cost of doing a full extents check (~10% on aa10text), we
introduce an approximate extents query (~1% on aa10text). The disparity
should be rare, and should be an overestimate to force redundant
clipping.
Reported-by: Clemens Eisserer <linuxhippy@gmail.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=70541
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/sna/sna_glyphs.c')
-rw-r--r-- | src/sna/sna_glyphs.c | 187 |
1 files changed, 138 insertions, 49 deletions
diff --git a/src/sna/sna_glyphs.c b/src/sna/sna_glyphs.c index b7ccb888..e656f417 100644 --- a/src/sna/sna_glyphs.c +++ b/src/sna/sna_glyphs.c @@ -310,8 +310,8 @@ glyph_extents(int nlist, GlyphPtr *glyphs, BoxPtr extents) { - int16_t x1, x2, y1, y2; - int16_t x, y; + int x1, x2, y1, y2; + int x, y; x1 = y1 = MAXSHORT; x2 = y2 = MINSHORT; @@ -347,10 +347,60 @@ glyph_extents(int nlist, } } - extents->x1 = x1; - extents->x2 = x2; - extents->y1 = y1; - extents->y2 = y2; + extents->x1 = x1 > MINSHORT ? x1 : MINSHORT; + extents->y1 = y1 > MINSHORT ? y1 : MINSHORT; + extents->x2 = x2 < MAXSHORT ? x2 : MAXSHORT; + extents->y2 = y2 < MAXSHORT ? y2 : MAXSHORT; +} + +static void +glyph_approx_extents(int nlist, + GlyphListPtr list, + GlyphPtr *glyphs, + BoxPtr extents) +{ + int x1, x2, y1, y2; + int x, y; + + x1 = y1 = MAXSHORT; + x2 = y2 = MINSHORT; + + x = y = 0; + while (nlist--) { + int n = list->len; + x += list->xOff; + if (x < x1) + x1 = x; + if (x > x2) + x2 = x; + + y += list->yOff; + if (y < y1) + y1 = y; + if (y > y2) + y2 = y; + + list++; + while (n--) { + GlyphPtr glyph = *glyphs++; + x += glyph->info.xOff; + y += glyph->info.yOff; + } + + if (y < y1) + y1 = y; + if (y > y2) + y2 = y; + if (x < x1) + x1 = x; + if (x > x2) + x2 = x; + } + + extents->x1 = x1 > MINSHORT ? x1 : MINSHORT; + extents->y1 = y1 > MINSHORT ? y1 : MINSHORT; + extents->x2 = x2 < MAXSHORT ? x2 : MAXSHORT; + extents->y2 = y2 < MAXSHORT ? y2 : MAXSHORT; } static inline unsigned int @@ -517,6 +567,37 @@ static void apply_damage_clipped_to_dst(struct sna_composite_op *op, sna_damage_add_box(op->damage, &box); } +static inline bool clipped_glyphs(PicturePtr dst, int nlist, GlyphListPtr list, GlyphPtr *glyphs) +{ + PixmapPtr pixmap; + BoxRec box; + + if (dst->pCompositeClip->data) { + DBG(("%s: yes, has complex region\n", __FUNCTION__)); + return true; + } + + pixmap = get_drawable_pixmap(dst->pDrawable); + if (dst->pCompositeClip->extents.x2 - dst->pCompositeClip->extents.x1 >= pixmap->drawable.width && + dst->pCompositeClip->extents.y2 - dst->pCompositeClip->extents.y1 >= pixmap->drawable.height) { + DBG(("%s: no, region matches drawable\n", __FUNCTION__)); + return false; + } + + glyph_approx_extents(nlist, list, glyphs, &box); + DBG(("%s? glyph extents (%d, %d), (%d, %d), region (%d, %d), (%d, %d): %s\n", + __FUNCTION__, box.x1, box.y1, box.x2, box.y2, + dst->pCompositeClip->extents.x1, dst->pCompositeClip->extents.y1, dst->pCompositeClip->extents.x2, dst->pCompositeClip->extents.y2, + (box.x1 < dst->pCompositeClip->extents.x1 || + box.y1 < dst->pCompositeClip->extents.y1 || + box.x2 > dst->pCompositeClip->extents.x2 || + box.y2 > dst->pCompositeClip->extents.y2) ? "yes" : "no")); + return (box.x1 < dst->pCompositeClip->extents.x1 || + box.y1 < dst->pCompositeClip->extents.y1 || + box.x2 > dst->pCompositeClip->extents.x2 || + box.y2 > dst->pCompositeClip->extents.y2); +} + flatten static bool glyphs_to_dst(struct sna *sna, CARD8 op, @@ -541,7 +622,7 @@ glyphs_to_dst(struct sna *sna, __FUNCTION__, op, src_x, src_y, nlist, list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y)); - if (is_clipped(dst->pCompositeClip, dst->pDrawable)) { + if (clipped_glyphs(dst, nlist, list, glyphs)) { rects = REGION_RECTS(dst->pCompositeClip); nrect = REGION_NUM_RECTS(dst->pCompositeClip); } else @@ -683,7 +764,7 @@ glyphs0_to_dst(struct sna *sna, PicturePtr glyph_atlas; BoxPtr rects; int nrect; - int16_t x, y; + int x, y; if (NO_GLYPHS_TO_DST) return false; @@ -694,7 +775,7 @@ glyphs0_to_dst(struct sna *sna, __FUNCTION__, op, src_x, src_y, nlist, list->xOff, list->yOff, dst->pDrawable->x, dst->pDrawable->y)); - if (is_clipped(dst->pCompositeClip, dst->pDrawable)) { + if (clipped_glyphs(dst, nlist, list, glyphs)) { rects = REGION_RECTS(dst->pCompositeClip); nrect = REGION_NUM_RECTS(dst->pCompositeClip); } else @@ -750,46 +831,54 @@ glyphs0_to_dst(struct sna *sna, } if (nrect) { - for (i = 0; i < nrect; i++) { - struct sna_composite_rectangles r; - int16_t dx, dy; - int16_t x2, y2; - - r.dst.x = x - glyph->info.x; - r.dst.y = y - glyph->info.y; - x2 = r.dst.x + glyph->info.width; - y2 = r.dst.y + glyph->info.height; - dx = dy = 0; - - DBG(("%s: glyph=(%d, %d), (%d, %d), clip=(%d, %d), (%d, %d)\n", - __FUNCTION__, - r.dst.x, r.dst.y, x2, y2, - rects[i].x1, rects[i].y1, - rects[i].x2, rects[i].y2)); - if (rects[i].y1 >= y2) - break; - - if (r.dst.x < rects[i].x1) - dx = rects[i].x1 - r.dst.x, r.dst.x = rects[i].x1; - if (x2 > rects[i].x2) - x2 = rects[i].x2; - if (r.dst.y < rects[i].y1) - dy = rects[i].y1 - r.dst.y, r.dst.y = rects[i].y1; - if (y2 > rects[i].y2) - y2 = rects[i].y2; - - if (r.dst.x < x2 && r.dst.y < y2) { - DBG(("%s: blt=(%d, %d), (%d, %d)\n", - __FUNCTION__, r.dst.x, r.dst.y, x2, y2)); - - r.src.x = r.dst.x + src_x; - r.src.y = r.dst.y + src_y; - r.mask.x = dx + p->coordinate.x; - r.mask.y = dy + p->coordinate.y; - r.width = x2 - r.dst.x; - r.height = y2 - r.dst.y; - tmp.blt(sna, &tmp, &r); - apply_damage(&tmp, &r); + int xi = x - glyph->info.x; + int yi = y - glyph->info.y; + + if (xi < dst->pCompositeClip->extents.x2 && + yi < dst->pCompositeClip->extents.y2 && + xi + glyph->info.width > dst->pCompositeClip->extents.x1 && + yi + glyph->info.height > dst->pCompositeClip->extents.y1) { + for (i = 0; i < nrect; i++) { + struct sna_composite_rectangles r; + int16_t dx, dy; + int16_t x2, y2; + + r.dst.x = x - glyph->info.x; + r.dst.y = y - glyph->info.y; + x2 = r.dst.x + glyph->info.width; + y2 = r.dst.y + glyph->info.height; + dx = dy = 0; + + DBG(("%s: glyph=(%d, %d), (%d, %d), clip=(%d, %d), (%d, %d)\n", + __FUNCTION__, + r.dst.x, r.dst.y, x2, y2, + rects[i].x1, rects[i].y1, + rects[i].x2, rects[i].y2)); + if (rects[i].y1 >= y2) + break; + + if (r.dst.x < rects[i].x1) + dx = rects[i].x1 - r.dst.x, r.dst.x = rects[i].x1; + if (x2 > rects[i].x2) + x2 = rects[i].x2; + if (r.dst.y < rects[i].y1) + dy = rects[i].y1 - r.dst.y, r.dst.y = rects[i].y1; + if (y2 > rects[i].y2) + y2 = rects[i].y2; + + if (r.dst.x < x2 && r.dst.y < y2) { + DBG(("%s: blt=(%d, %d), (%d, %d)\n", + __FUNCTION__, r.dst.x, r.dst.y, x2, y2)); + + r.src.x = r.dst.x + src_x; + r.src.y = r.dst.y + src_y; + r.mask.x = dx + p->coordinate.x; + r.mask.y = dy + p->coordinate.y; + r.width = x2 - r.dst.x; + r.height = y2 - r.dst.y; + tmp.blt(sna, &tmp, &r); + apply_damage(&tmp, &r); + } } } } else { |