Always round text position correctly.
https://codereview.appspot.com/7383049/ Will require rebaseline of fontscaler GM. Must add SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX to Chromium until ~150 layout tests can be rebaselined. git-svn-id: http://skia.googlecode.com/svn/trunk@7842 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
570ed6466c
commit
9447103029
@ -1606,6 +1606,12 @@ SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter,
|
|||||||
fBlitter = blitter;
|
fBlitter = blitter;
|
||||||
fCache = cache;
|
fCache = cache;
|
||||||
|
|
||||||
|
if (cache->isSubpixel()) {
|
||||||
|
fHalfSampleX = fHalfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
|
||||||
|
} else {
|
||||||
|
fHalfSampleX = fHalfSampleY = SK_FixedHalf;
|
||||||
|
}
|
||||||
|
|
||||||
if (hasCustomD1GProc(*draw)) {
|
if (hasCustomD1GProc(*draw)) {
|
||||||
// todo: fix this assumption about clips w/ custom
|
// todo: fix this assumption about clips w/ custom
|
||||||
fClip = draw->fClip;
|
fClip = draw->fClip;
|
||||||
@ -1662,15 +1668,13 @@ void SkDraw::drawText(const char text[], size_t byteLength,
|
|||||||
|
|
||||||
SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc();
|
SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc();
|
||||||
|
|
||||||
const SkMatrix* matrix = fMatrix;
|
SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, fMatrix);
|
||||||
|
|
||||||
SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, matrix);
|
|
||||||
SkGlyphCache* cache = autoCache.getCache();
|
SkGlyphCache* cache = autoCache.getCache();
|
||||||
|
|
||||||
// transform our starting point
|
// transform our starting point
|
||||||
{
|
{
|
||||||
SkPoint loc;
|
SkPoint loc;
|
||||||
matrix->mapXY(x, y, &loc);
|
fMatrix->mapXY(x, y, &loc);
|
||||||
x = loc.fX;
|
x = loc.fX;
|
||||||
y = loc.fY;
|
y = loc.fY;
|
||||||
}
|
}
|
||||||
@ -1692,33 +1696,13 @@ void SkDraw::drawText(const char text[], size_t byteLength,
|
|||||||
y -= stopY;
|
y -= stopY;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkFixed fx = SkScalarToFixed(x);
|
|
||||||
SkFixed fy = SkScalarToFixed(y);
|
|
||||||
const char* stop = text + byteLength;
|
const char* stop = text + byteLength;
|
||||||
|
|
||||||
SkFixed fxMask = ~0;
|
|
||||||
SkFixed fyMask = ~0;
|
|
||||||
if (cache->isSubpixel()) {
|
|
||||||
SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*matrix);
|
|
||||||
if (kX_SkAxisAlignment == baseline) {
|
|
||||||
fyMask = 0;
|
|
||||||
} else if (kY_SkAxisAlignment == baseline) {
|
|
||||||
fxMask = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply bias here to avoid adding 1/2 the sampling frequency in the loop
|
|
||||||
fx += SK_FixedHalf >> SkGlyph::kSubBits;
|
|
||||||
fy += SK_FixedHalf >> SkGlyph::kSubBits;
|
|
||||||
} else {
|
|
||||||
fx += SK_FixedHalf;
|
|
||||||
fy += SK_FixedHalf;
|
|
||||||
}
|
|
||||||
|
|
||||||
SkAAClipBlitter aaBlitter;
|
SkAAClipBlitter aaBlitter;
|
||||||
SkAutoBlitterChoose blitterChooser;
|
SkAutoBlitterChoose blitterChooser;
|
||||||
SkBlitter* blitter = NULL;
|
SkBlitter* blitter = NULL;
|
||||||
if (needsRasterTextBlit(*this)) {
|
if (needsRasterTextBlit(*this)) {
|
||||||
blitterChooser.choose(*fBitmap, *matrix, paint);
|
blitterChooser.choose(*fBitmap, *fMatrix, paint);
|
||||||
blitter = blitterChooser.get();
|
blitter = blitterChooser.get();
|
||||||
if (fRC->isAA()) {
|
if (fRC->isAA()) {
|
||||||
aaBlitter.init(blitter, &fRC->aaRgn());
|
aaBlitter.init(blitter, &fRC->aaRgn());
|
||||||
@ -1730,6 +1714,22 @@ void SkDraw::drawText(const char text[], size_t byteLength,
|
|||||||
SkDraw1Glyph d1g;
|
SkDraw1Glyph d1g;
|
||||||
SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache);
|
SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache);
|
||||||
|
|
||||||
|
SkFixed fxMask = ~0;
|
||||||
|
SkFixed fyMask = ~0;
|
||||||
|
if (cache->isSubpixel()) {
|
||||||
|
SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix);
|
||||||
|
if (kX_SkAxisAlignment == baseline) {
|
||||||
|
fyMask = 0;
|
||||||
|
d1g.fHalfSampleY = SK_FixedHalf;
|
||||||
|
} else if (kY_SkAxisAlignment == baseline) {
|
||||||
|
fxMask = 0;
|
||||||
|
d1g.fHalfSampleX = SK_FixedHalf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SkFixed fx = SkScalarToFixed(x) + d1g.fHalfSampleX;
|
||||||
|
SkFixed fy = SkScalarToFixed(y) + d1g.fHalfSampleY;
|
||||||
|
|
||||||
while (text < stop) {
|
while (text < stop) {
|
||||||
const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
|
const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
|
||||||
|
|
||||||
@ -1855,17 +1855,15 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SkMatrix* matrix = fMatrix;
|
|
||||||
|
|
||||||
SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc();
|
SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc();
|
||||||
SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, matrix);
|
SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, fMatrix);
|
||||||
SkGlyphCache* cache = autoCache.getCache();
|
SkGlyphCache* cache = autoCache.getCache();
|
||||||
|
|
||||||
SkAAClipBlitterWrapper wrapper;
|
SkAAClipBlitterWrapper wrapper;
|
||||||
SkAutoBlitterChoose blitterChooser;
|
SkAutoBlitterChoose blitterChooser;
|
||||||
SkBlitter* blitter = NULL;
|
SkBlitter* blitter = NULL;
|
||||||
if (needsRasterTextBlit(*this)) {
|
if (needsRasterTextBlit(*this)) {
|
||||||
blitterChooser.choose(*fBitmap, *matrix, paint);
|
blitterChooser.choose(*fBitmap, *fMatrix, paint);
|
||||||
blitter = blitterChooser.get();
|
blitter = blitterChooser.get();
|
||||||
if (fRC->isAA()) {
|
if (fRC->isAA()) {
|
||||||
wrapper.init(*fRC, blitter);
|
wrapper.init(*fRC, blitter);
|
||||||
@ -1877,29 +1875,33 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
|
|||||||
AlignProc alignProc = pick_align_proc(paint.getTextAlign());
|
AlignProc alignProc = pick_align_proc(paint.getTextAlign());
|
||||||
SkDraw1Glyph d1g;
|
SkDraw1Glyph d1g;
|
||||||
SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache);
|
SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache);
|
||||||
TextMapState tms(*matrix, constY);
|
TextMapState tms(*fMatrix, constY);
|
||||||
TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition);
|
TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition);
|
||||||
|
|
||||||
if (cache->isSubpixel()) {
|
if (cache->isSubpixel()) {
|
||||||
// maybe we should skip the rounding if linearText is set
|
// maybe we should skip the rounding if linearText is set
|
||||||
SkAxisAlignment roundBaseline = SkComputeAxisAlignmentForHText(*matrix);
|
SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix);
|
||||||
|
|
||||||
|
SkFixed fxMask = ~0;
|
||||||
|
SkFixed fyMask = ~0;
|
||||||
|
if (kX_SkAxisAlignment == baseline) {
|
||||||
|
fyMask = 0;
|
||||||
|
#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
|
||||||
|
d1g.fHalfSampleY = SK_FixedHalf;
|
||||||
|
#endif
|
||||||
|
} else if (kY_SkAxisAlignment == baseline) {
|
||||||
|
fxMask = 0;
|
||||||
|
#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
|
||||||
|
d1g.fHalfSampleX = SK_FixedHalf;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (SkPaint::kLeft_Align == paint.getTextAlign()) {
|
if (SkPaint::kLeft_Align == paint.getTextAlign()) {
|
||||||
while (text < stop) {
|
while (text < stop) {
|
||||||
|
|
||||||
tmsProc(tms, pos);
|
tmsProc(tms, pos);
|
||||||
|
|
||||||
SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + (SK_FixedHalf >> SkGlyph::kSubBits);
|
SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + d1g.fHalfSampleX;
|
||||||
SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + (SK_FixedHalf >> SkGlyph::kSubBits);
|
SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + d1g.fHalfSampleY;
|
||||||
|
|
||||||
SkFixed fxMask = ~0;
|
|
||||||
SkFixed fyMask = ~0;
|
|
||||||
|
|
||||||
if (kX_SkAxisAlignment == roundBaseline) {
|
|
||||||
fyMask = 0;
|
|
||||||
} else if (kY_SkAxisAlignment == roundBaseline) {
|
|
||||||
fxMask = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SkGlyph& glyph = glyphCacheProc(cache, &text,
|
const SkGlyph& glyph = glyphCacheProc(cache, &text,
|
||||||
fx & fxMask, fy & fyMask);
|
fx & fxMask, fy & fyMask);
|
||||||
@ -1912,38 +1914,28 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
|
|||||||
} else {
|
} else {
|
||||||
while (text < stop) {
|
while (text < stop) {
|
||||||
const char* currentText = text;
|
const char* currentText = text;
|
||||||
const SkGlyph* glyph = &glyphCacheProc(cache, &text, 0, 0);
|
const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
|
||||||
|
|
||||||
if (glyph->fWidth) {
|
if (metricGlyph.fWidth) {
|
||||||
SkDEBUGCODE(SkFixed prevAdvX = glyph->fAdvanceX;)
|
SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
|
||||||
SkDEBUGCODE(SkFixed prevAdvY = glyph->fAdvanceY;)
|
SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
|
||||||
|
|
||||||
SkFixed fx, fy;
|
|
||||||
SkFixed fxMask = ~0;
|
|
||||||
SkFixed fyMask = ~0;
|
|
||||||
tmsProc(tms, pos);
|
tmsProc(tms, pos);
|
||||||
|
SkIPoint fixedLoc;
|
||||||
|
alignProc(tms.fLoc, metricGlyph, &fixedLoc);
|
||||||
|
|
||||||
{
|
SkFixed fx = fixedLoc.fX + d1g.fHalfSampleX;
|
||||||
SkIPoint fixedLoc;
|
SkFixed fy = fixedLoc.fY + d1g.fHalfSampleY;
|
||||||
alignProc(tms.fLoc, *glyph, &fixedLoc);
|
|
||||||
fx = fixedLoc.fX + (SK_FixedHalf >> SkGlyph::kSubBits);
|
|
||||||
fy = fixedLoc.fY + (SK_FixedHalf >> SkGlyph::kSubBits);
|
|
||||||
|
|
||||||
if (kX_SkAxisAlignment == roundBaseline) {
|
|
||||||
fyMask = 0;
|
|
||||||
} else if (kY_SkAxisAlignment == roundBaseline) {
|
|
||||||
fxMask = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// have to call again, now that we've been "aligned"
|
// have to call again, now that we've been "aligned"
|
||||||
glyph = &glyphCacheProc(cache, ¤tText,
|
const SkGlyph& glyph = glyphCacheProc(cache, ¤tText,
|
||||||
fx & fxMask, fy & fyMask);
|
fx & fxMask, fy & fyMask);
|
||||||
// the assumption is that the advance hasn't changed
|
// the assumption is that the metrics haven't changed
|
||||||
SkASSERT(prevAdvX == glyph->fAdvanceX);
|
SkASSERT(prevAdvX == glyph.fAdvanceX);
|
||||||
SkASSERT(prevAdvY == glyph->fAdvanceY);
|
SkASSERT(prevAdvY == glyph.fAdvanceY);
|
||||||
|
SkASSERT(glyph.fWidth);
|
||||||
|
|
||||||
proc(d1g, fx, fy, *glyph);
|
proc(d1g, fx, fy, glyph);
|
||||||
}
|
}
|
||||||
pos += scalarsPerPosition;
|
pos += scalarsPerPosition;
|
||||||
}
|
}
|
||||||
@ -1958,8 +1950,8 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
|
|||||||
tmsProc(tms, pos);
|
tmsProc(tms, pos);
|
||||||
|
|
||||||
proc(d1g,
|
proc(d1g,
|
||||||
SkScalarToFixed(tms.fLoc.fX) + SK_FixedHalf,
|
SkScalarToFixed(tms.fLoc.fX) + SK_FixedHalf, //d1g.fHalfSampleX,
|
||||||
SkScalarToFixed(tms.fLoc.fY) + SK_FixedHalf,
|
SkScalarToFixed(tms.fLoc.fY) + SK_FixedHalf, //d1g.fHalfSampleY,
|
||||||
glyph);
|
glyph);
|
||||||
}
|
}
|
||||||
pos += scalarsPerPosition;
|
pos += scalarsPerPosition;
|
||||||
@ -1976,8 +1968,8 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
|
|||||||
alignProc(tms.fLoc, glyph, &fixedLoc);
|
alignProc(tms.fLoc, glyph, &fixedLoc);
|
||||||
|
|
||||||
proc(d1g,
|
proc(d1g,
|
||||||
fixedLoc.fX + SK_FixedHalf,
|
fixedLoc.fX + SK_FixedHalf, //d1g.fHalfSampleX,
|
||||||
fixedLoc.fY + SK_FixedHalf,
|
fixedLoc.fY + SK_FixedHalf, //d1g.fHalfSampleY,
|
||||||
glyph);
|
glyph);
|
||||||
}
|
}
|
||||||
pos += scalarsPerPosition;
|
pos += scalarsPerPosition;
|
||||||
|
@ -21,10 +21,18 @@ struct SkDraw1Glyph {
|
|||||||
SkBlitter* fBlitter;
|
SkBlitter* fBlitter;
|
||||||
SkGlyphCache* fCache;
|
SkGlyphCache* fCache;
|
||||||
SkIRect fClipBounds;
|
SkIRect fClipBounds;
|
||||||
|
/** Half the sampling frequency of the rasterized glyph in x. */
|
||||||
|
SkFixed fHalfSampleX;
|
||||||
|
/** Half the sampling frequency of the rasterized glyph in y. */
|
||||||
|
SkFixed fHalfSampleY;
|
||||||
|
|
||||||
// The fixed x,y are pre-rounded, so impls just trunc them down to ints.
|
/** Draws one glyph.
|
||||||
// i.e. half the sampling frequency has been added.
|
*
|
||||||
// e.g. 1/2 or 1/(2^(SkGlyph::kSubBits+1)) has already been added.
|
* The x and y are pre-biased, so implementations may just truncate them.
|
||||||
|
* i.e. half the sampling frequency has been added.
|
||||||
|
* e.g. 1/2 or 1/(2^(SkGlyph::kSubBits+1)) has already been added.
|
||||||
|
* This added bias can be found in fHalfSampleX,Y.
|
||||||
|
*/
|
||||||
typedef void (*Proc)(const SkDraw1Glyph&, SkFixed x, SkFixed y, const SkGlyph&);
|
typedef void (*Proc)(const SkDraw1Glyph&, SkFixed x, SkFixed y, const SkGlyph&);
|
||||||
|
|
||||||
Proc init(const SkDraw* draw, SkBlitter* blitter, SkGlyphCache* cache);
|
Proc init(const SkDraw* draw, SkBlitter* blitter, SkGlyphCache* cache);
|
||||||
|
@ -2182,13 +2182,8 @@ static void xps_draw_1_glyph(const SkDraw1Glyph& state,
|
|||||||
SkXPSDrawProcs* procs = static_cast<SkXPSDrawProcs*>(state.fDraw->fProcs);
|
SkXPSDrawProcs* procs = static_cast<SkXPSDrawProcs*>(state.fDraw->fProcs);
|
||||||
|
|
||||||
//Draw pre-adds half the sampling frequency for floor rounding.
|
//Draw pre-adds half the sampling frequency for floor rounding.
|
||||||
if (state.fCache->isSubpixel()) {
|
x -= state.fHalfSampleX;
|
||||||
x -= (SK_FixedHalf >> SkGlyph::kSubBits);
|
y -= state.fHalfSampleY;
|
||||||
y -= (SK_FixedHalf >> SkGlyph::kSubBits);
|
|
||||||
} else {
|
|
||||||
x -= SK_FixedHalf;
|
|
||||||
y -= SK_FixedHalf;
|
|
||||||
}
|
|
||||||
|
|
||||||
XPS_GLYPH_INDEX* xpsGlyph = procs->xpsGlyphs.append();
|
XPS_GLYPH_INDEX* xpsGlyph = procs->xpsGlyphs.append();
|
||||||
uint16_t glyphID = skGlyph.getGlyphID();
|
uint16_t glyphID = skGlyph.getGlyphID();
|
||||||
|
@ -145,7 +145,7 @@ static void test_advances(skiatest::Reporter* reporter) {
|
|||||||
char txt[] = "long.text.with.lots.of.dots.";
|
char txt[] = "long.text.with.lots.of.dots.";
|
||||||
|
|
||||||
for (size_t i = 0; i < SK_ARRAY_COUNT(faces); i++) {
|
for (size_t i = 0; i < SK_ARRAY_COUNT(faces); i++) {
|
||||||
SkTypeface* face = SkTypeface::CreateFromName(faces[i], SkTypeface::kNormal);
|
SkAutoTUnref<SkTypeface> face(SkTypeface::CreateFromName(faces[i], SkTypeface::kNormal));
|
||||||
paint.setTypeface(face);
|
paint.setTypeface(face);
|
||||||
|
|
||||||
for (size_t j = 0; j < SK_ARRAY_COUNT(settings); j++) {
|
for (size_t j = 0; j < SK_ARRAY_COUNT(settings); j++) {
|
||||||
|
Loading…
Reference in New Issue
Block a user