Replace D1G with a simpler implementation.

Review URL: https://codereview.chromium.org/1403573002
This commit is contained in:
herb 2015-12-01 09:50:04 -08:00 committed by Commit bot
parent aa0df4e98d
commit 001e744266

View File

@ -1423,62 +1423,33 @@ void SkDraw::drawText_asPaths(const char text[], size_t byteLength,
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////
struct SkDraw1Glyph {
const SkDraw* fDraw;
const SkRegion* fClip;
const SkAAClip* fAAClip;
SkBlitter* fBlitter;
SkGlyphCache* fCache;
const SkPaint* fPaint;
SkIRect fClipBounds;
/** Half the sampling frequency of the rasterized glyph in x. */
SkScalar fHalfSampleX;
/** Half the sampling frequency of the rasterized glyph in y. */
SkScalar fHalfSampleY;
/** Draws one glyph.
*
* 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&, Sk48Dot16 x, Sk48Dot16 y, const SkGlyph&);
class DrawOneGlyph {
public:
DrawOneGlyph(const SkDraw& draw, const SkPaint& paint, SkGlyphCache* cache, SkBlitter* blitter)
: fUseRegionToDraw(UsingRegionToDraw(draw.fRC))
, fGlyphCache(cache)
, fBlitter(blitter)
, fClip(fUseRegionToDraw ? &draw.fRC->bwRgn() : nullptr)
, fDraw(draw)
, fPaint(paint)
, fClipBounds(PickClipBounds(draw)) { }
Proc init(const SkDraw* draw, SkBlitter* blitter, SkGlyphCache* cache,
const SkPaint&);
// call this instead of fBlitter->blitMask() since this wrapper will handle
// the case when the mask is ARGB32_Format
//
void blitMask(const SkMask& mask, const SkIRect& clip) const {
if (SkMask::kARGB32_Format == mask.fFormat) {
this->blitMaskAsSprite(mask);
} else {
fBlitter->blitMask(mask, clip);
}
}
// mask must be kARGB32_Format
void blitMaskAsSprite(const SkMask& mask) const;
};
static void D1G_RectClip(const SkDraw1Glyph& state, Sk48Dot16 fx, Sk48Dot16 fy,
const SkGlyph& glyph) {
void operator()(const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
position += rounding;
Sk48Dot16 fx = SkScalarTo48Dot16(position.fX);
Sk48Dot16 fy = SkScalarTo48Dot16(position.fY);
// Prevent glyphs from being drawn outside of or straddling the edge of device space.
if ((fx >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) ||
(fx >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/) ||
(fy >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) ||
(fy >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/))
{
(fy >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) {
return;
}
int left = Sk48Dot16FloorToInt(fx);
int top = Sk48Dot16FloorToInt(fy);
SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
SkASSERT((nullptr == state.fClip && state.fAAClip) ||
(state.fClip && nullptr == state.fAAClip && state.fClip->isRect()));
left += glyph.fLeft;
top += glyph.fTop;
@ -1487,106 +1458,85 @@ static void D1G_RectClip(const SkDraw1Glyph& state, Sk48Dot16 fx, Sk48Dot16 fy,
int bottom = top + glyph.fHeight;
SkMask mask;
mask.fBounds.set(left, top, right, bottom);
if (fUseRegionToDraw) {
SkRegion::Cliperator clipper(*fClip, mask.fBounds);
if (!clipper.done() && this->getImageData(glyph, &mask)) {
const SkIRect& cr = clipper.rect();
do {
this->blitMask(mask, cr);
clipper.next();
} while (!clipper.done());
}
} else {
SkIRect storage;
SkIRect* bounds = &mask.fBounds;
mask.fBounds.set(left, top, right, bottom);
// this extra test is worth it, assuming that most of the time it succeeds
// since we can avoid writing to storage
if (!state.fClipBounds.containsNoEmptyCheck(left, top, right, bottom)) {
if (!storage.intersectNoEmptyCheck(mask.fBounds, state.fClipBounds))
if (!fClipBounds.containsNoEmptyCheck(mask.fBounds)) {
if (!storage.intersectNoEmptyCheck(mask.fBounds, fClipBounds))
return;
bounds = &storage;
}
uint8_t* aa = (uint8_t*)glyph.fImage;
if (nullptr == aa) {
aa = (uint8_t*)state.fCache->findImage(glyph);
if (nullptr == aa) {
return; // can't rasterize glyph
if (this->getImageData(glyph, &mask)) {
this->blitMask(mask, *bounds);
}
}
}
mask.fRowBytes = glyph.rowBytes();
mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
mask.fImage = aa;
state.blitMask(mask, *bounds);
private:
static bool UsingRegionToDraw(const SkRasterClip* rClip) {
return rClip->isBW() && !rClip->isRect();
}
static void D1G_RgnClip(const SkDraw1Glyph& state, Sk48Dot16 fx, Sk48Dot16 fy,
const SkGlyph& glyph) {
int left = Sk48Dot16FloorToInt(fx);
int top = Sk48Dot16FloorToInt(fy);
SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
SkASSERT(!state.fClip->isRect());
static SkIRect PickClipBounds(const SkDraw& draw) {
const SkRasterClip& rasterClip = *draw.fRC;
SkMask mask;
left += glyph.fLeft;
top += glyph.fTop;
mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
SkRegion::Cliperator clipper(*state.fClip, mask.fBounds);
if (!clipper.done()) {
const SkIRect& cr = clipper.rect();
const uint8_t* aa = (uint8_t*)state.fCache->findImage(glyph);
if (nullptr == aa) {
return;
}
mask.fRowBytes = glyph.rowBytes();
mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
mask.fImage = (uint8_t*)aa;
do {
state.blitMask(mask, cr);
clipper.next();
} while (!clipper.done());
}
}
SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter, SkGlyphCache* cache,
const SkPaint& pnt) {
fDraw = draw;
fBlitter = blitter;
fCache = cache;
fPaint = &pnt;
if (cache->isSubpixel()) {
fHalfSampleX = fHalfSampleY = SkFixedToScalar(SkGlyph::kSubpixelRound);
if (rasterClip.isBW()) {
return rasterClip.bwRgn().getBounds();
} else {
fHalfSampleX = fHalfSampleY = SK_ScalarHalf;
}
if (draw->fRC->isBW()) {
fAAClip = nullptr;
fClip = &draw->fRC->bwRgn();
fClipBounds = fClip->getBounds();
if (fClip->isRect()) {
return D1G_RectClip;
} else {
return D1G_RgnClip;
}
} else { // aaclip
fAAClip = &draw->fRC->aaRgn();
fClip = nullptr;
fClipBounds = fAAClip->getBounds();
return D1G_RectClip;
return rasterClip.aaRgn().getBounds();
}
}
void SkDraw1Glyph::blitMaskAsSprite(const SkMask& mask) const {
SkASSERT(SkMask::kARGB32_Format == mask.fFormat);
bool getImageData(const SkGlyph& glyph, SkMask* mask) {
uint8_t* bits = (uint8_t*)(fGlyphCache->findImage(glyph));
if (nullptr == bits) {
return false; // can't rasterize glyph
}
mask->fImage = bits;
mask->fRowBytes = glyph.rowBytes();
mask->fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
return true;
}
void blitMask(const SkMask& mask, const SkIRect& clip) const {
if (SkMask::kARGB32_Format == mask.fFormat) {
SkBitmap bm;
bm.installPixels(SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()),
bm.installPixels(
SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()),
(SkPMColor*)mask.fImage, mask.fRowBytes);
fDraw->drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), *fPaint);
fDraw.drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), fPaint);
} else {
fBlitter->blitMask(mask, clip);
}
}
///////////////////////////////////////////////////////////////////////////////
const bool fUseRegionToDraw;
SkGlyphCache * const fGlyphCache;
SkBlitter * const fBlitter;
const SkRegion* const fClip;
const SkDraw& fDraw;
const SkPaint& fPaint;
const SkIRect fClipBounds;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
void SkDraw::drawText(const char text[], size_t byteLength,
SkScalar x, SkScalar y, const SkPaint& paint) const {
@ -1609,22 +1559,14 @@ void SkDraw::drawText(const char text[], size_t byteLength,
SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix);
SkGlyphCache* cache = autoCache.getCache();
// The Blitter Choose needs to be live while using the blitter below.
SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
SkDraw1Glyph d1g;
SkDraw1Glyph::Proc proc = d1g.init(this, wrapper.getBlitter(), cache, paint);
DrawOneGlyph drawOneGlyph(*this, paint, cache, wrapper.getBlitter());
SkFindAndPlaceGlyph::ProcessText(
paint.getTextEncoding(), text, byteLength,
{x, y}, *fMatrix, paint.getTextAlign(), cache,
[&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
position += rounding;
proc(d1g, SkScalarTo48Dot16(position.fX), SkScalarTo48Dot16(position.fY), glyph);
}
);
{x, y}, *fMatrix, paint.getTextAlign(), cache, drawOneGlyph);
}
//////////////////////////////////////////////////////////////////////////////
@ -1696,24 +1638,18 @@ void SkDraw::drawPosText(const char text[], size_t byteLength,
return;
}
SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix);
SkGlyphCache* cache = autoCache.getCache();
// The Blitter Choose needs to be live while using the blitter below.
SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix);
SkGlyphCache* cache = autoCache.getCache();
SkDraw1Glyph d1g;
SkDraw1Glyph::Proc proc = d1g.init(this, wrapper.getBlitter(), cache, paint);
DrawOneGlyph drawOneGlyph(*this, paint, cache, wrapper.getBlitter());
SkPaint::Align textAlignment = paint.getTextAlign();
SkFindAndPlaceGlyph::ProcessPosText(
paint.getTextEncoding(), text, byteLength,
offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache,
[&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
position += rounding;
proc(d1g, SkScalarTo48Dot16(position.fX), SkScalarTo48Dot16(position.fY), glyph);
}
);
offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache, drawOneGlyph);
}
#if defined _WIN32 && _MSC_VER >= 1300