Simplify nvpr text
- Drops device-space glyphs in favor of perf/simplicity. - Removes residual complexities that would flip glyphs vertically for compatibility with nvpr glyph loading, which is no longer used. - Drops hairline support since they required new paths for every draw matrix, and could only be supported under certain circumstances. - Quits checking for color bitmap fonts in canDrawText since the normal color emoji fallback will handle them anyway. BUG=skia: Review URL: https://codereview.chromium.org/1380973002
This commit is contained in:
parent
19ae315dd0
commit
7d5c950e85
@ -19,9 +19,7 @@ public:
|
||||
#ifdef SK_DEBUG
|
||||
, fDesc(desc.copy())
|
||||
#endif
|
||||
{
|
||||
fFlipMatrix.setScale(1, -1);
|
||||
}
|
||||
{}
|
||||
|
||||
virtual ~GlyphGenerator() {
|
||||
#ifdef SK_DEBUG
|
||||
@ -39,7 +37,6 @@ public:
|
||||
fScalerContext->getMetrics(&skGlyph);
|
||||
|
||||
fScalerContext->getPath(skGlyph, out);
|
||||
out->transform(fFlipMatrix); // Load glyphs with the inverted y-direction.
|
||||
}
|
||||
#ifdef SK_DEBUG
|
||||
bool isEqualTo(const SkDescriptor& desc) const override {
|
||||
@ -48,7 +45,6 @@ public:
|
||||
#endif
|
||||
private:
|
||||
const SkAutoTDelete<SkScalerContext> fScalerContext;
|
||||
SkMatrix fFlipMatrix;
|
||||
#ifdef SK_DEBUG
|
||||
SkDescriptor* const fDesc;
|
||||
#endif
|
||||
|
@ -58,18 +58,8 @@ bool GrStencilAndCoverTextContext::canDraw(const GrRenderTarget* rt,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// No hairlines unless we can map the 1 px width to the object space.
|
||||
if (skPaint.getStyle() == SkPaint::kStroke_Style
|
||||
&& skPaint.getStrokeWidth() == 0
|
||||
&& viewMatrix.hasPerspective()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// No color bitmap fonts.
|
||||
SkScalerContext::Rec rec;
|
||||
SkScalerContext::MakeRec(skPaint, &fSurfaceProps, nullptr, &rec);
|
||||
return rec.getFormat() != SkMask::kARGB32_Format;
|
||||
// No hairlines. They would require new paths with customized strokes for every new draw matrix.
|
||||
return SkPaint::kStroke_Style != skPaint.getStyle() || 0 != skPaint.getStrokeWidth();
|
||||
}
|
||||
|
||||
void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget* rt,
|
||||
@ -87,31 +77,7 @@ void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget*
|
||||
return;
|
||||
}
|
||||
|
||||
// This is the slow path, mainly used by Skia unit tests. The other
|
||||
// backends (8888, gpu, ...) use device-space dependent glyph caches. In
|
||||
// order to match the glyph positions that the other code paths produce, we
|
||||
// must also use device-space dependent glyph cache. This has the
|
||||
// side-effect that the glyph shape outline will be in device-space,
|
||||
// too. This in turn has the side-effect that NVPR can not stroke the paths,
|
||||
// as the stroke in NVPR is defined in object-space.
|
||||
// NOTE: here we have following coincidence that works at the moment:
|
||||
// - When using the device-space glyphs, the transforms we pass to NVPR
|
||||
// instanced drawing are the global transforms, and the view transform is
|
||||
// identity. NVPR can not use non-affine transforms in the instanced
|
||||
// drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it
|
||||
// will turn off the use of device-space glyphs when perspective transforms
|
||||
// are in use.
|
||||
|
||||
this->init(rt, clip, paint, skPaint, byteLength, kMaxAccuracy_RenderMode, viewMatrix,
|
||||
regionClipBounds);
|
||||
|
||||
// Transform our starting point.
|
||||
if (fUsingDeviceSpaceGlyphs) {
|
||||
SkPoint loc;
|
||||
fContextInitialMatrix.mapXY(x, y, &loc);
|
||||
x = loc.fX;
|
||||
y = loc.fY;
|
||||
}
|
||||
this->init(rt, clip, paint, skPaint, byteLength, viewMatrix, regionClipBounds);
|
||||
|
||||
SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
|
||||
|
||||
@ -184,16 +150,7 @@ void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, GrRenderTarg
|
||||
return;
|
||||
}
|
||||
|
||||
// This is the fast path. Here we do not bake in the device-transform to
|
||||
// the glyph outline or the advances. This is because we do not need to
|
||||
// position the glyphs at all, since the caller has done the positioning.
|
||||
// The positioning is based on SkPaint::measureText of individual
|
||||
// glyphs. That already uses glyph cache without device transforms. Device
|
||||
// transform is not part of SkPaint::measureText API, and thus we use the
|
||||
// same glyphs as what were measured.
|
||||
|
||||
this->init(rt, clip, paint, skPaint, byteLength, kMaxPerformance_RenderMode, viewMatrix,
|
||||
regionClipBounds);
|
||||
this->init(rt, clip, paint, skPaint, byteLength, viewMatrix, regionClipBounds);
|
||||
|
||||
SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
|
||||
|
||||
@ -251,7 +208,6 @@ void GrStencilAndCoverTextContext::init(GrRenderTarget* rt,
|
||||
const GrPaint& paint,
|
||||
const SkPaint& skPaint,
|
||||
size_t textByteLength,
|
||||
RenderMode renderMode,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkIRect& regionClipBounds) {
|
||||
fClip = clip;
|
||||
@ -264,147 +220,69 @@ void GrStencilAndCoverTextContext::init(GrRenderTarget* rt,
|
||||
fPaint = paint;
|
||||
fSkPaint = skPaint;
|
||||
|
||||
fContextInitialMatrix = viewMatrix;
|
||||
fViewMatrix = viewMatrix;
|
||||
fLocalMatrix = SkMatrix::I();
|
||||
// Don't bake strokes into the glyph outlines. We will stroke the glyphs using the GPU instead.
|
||||
fStroke = GrStrokeInfo(fSkPaint);
|
||||
fSkPaint.setStyle(SkPaint::kFill_Style);
|
||||
|
||||
const bool otherBackendsWillDrawAsPaths =
|
||||
SkDraw::ShouldDrawTextAsPaths(skPaint, fContextInitialMatrix);
|
||||
SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported.
|
||||
|
||||
fUsingDeviceSpaceGlyphs = !otherBackendsWillDrawAsPaths &&
|
||||
kMaxAccuracy_RenderMode == renderMode &&
|
||||
SkToBool(fContextInitialMatrix.getType() &
|
||||
(SkMatrix::kScale_Mask | SkMatrix::kAffine_Mask));
|
||||
if (fSkPaint.isFakeBoldText() && SkStrokeRec::kStroke_Style != fStroke.getStyle()) {
|
||||
// Instead of baking fake bold into the glyph outlines, do it with the GPU stroke.
|
||||
SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(),
|
||||
kStdFakeBoldInterpKeys,
|
||||
kStdFakeBoldInterpValues,
|
||||
kStdFakeBoldInterpLength);
|
||||
SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale);
|
||||
fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extra : extra,
|
||||
true /*strokeAndFill*/);
|
||||
|
||||
if (fUsingDeviceSpaceGlyphs) {
|
||||
// SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms.
|
||||
SkASSERT(!fContextInitialMatrix.hasPerspective());
|
||||
fSkPaint.setFakeBoldText(false);
|
||||
}
|
||||
|
||||
// The whole shape (including stroke) will be baked into the glyph outlines. Make
|
||||
// NVPR just fill the baked shapes.
|
||||
fStroke = GrStrokeInfo(SkStrokeRec::kFill_InitStyle);
|
||||
bool canUseRawPaths;
|
||||
if (!fStroke.isDashed()) {
|
||||
// We can draw the glyphs from canonically sized paths.
|
||||
fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
|
||||
fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.getTextSize();
|
||||
|
||||
// Compensate for the glyphs being scaled by fTextRatio.
|
||||
if (!fStroke.isFillStyle()) {
|
||||
fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio,
|
||||
SkStrokeRec::kStrokeAndFill_Style == fStroke.getStyle());
|
||||
}
|
||||
|
||||
fSkPaint.setLinearText(true);
|
||||
fSkPaint.setLCDRenderText(false);
|
||||
fSkPaint.setAutohinted(false);
|
||||
fSkPaint.setHinting(SkPaint::kNo_Hinting);
|
||||
fSkPaint.setSubpixelText(true);
|
||||
fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
|
||||
|
||||
canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() &&
|
||||
0 == fSkPaint.getTextSkewX() &&
|
||||
!fSkPaint.isFakeBoldText() &&
|
||||
!fSkPaint.isVerticalText();
|
||||
} else {
|
||||
fTextRatio = fTextInverseRatio = 1.0f;
|
||||
canUseRawPaths = false;
|
||||
}
|
||||
|
||||
// Glyphs loaded by GPU path rendering have an inverted y-direction.
|
||||
SkMatrix m;
|
||||
m.setScale(1, -1);
|
||||
fViewMatrix = m;
|
||||
fViewMatrix = viewMatrix;
|
||||
fViewMatrix.preScale(fTextRatio, fTextRatio);
|
||||
fLocalMatrix.setScale(fTextRatio, fTextRatio);
|
||||
|
||||
// Post-flip the initial matrix so we're left with just the flip after
|
||||
// the paint preConcats the inverse.
|
||||
m = fContextInitialMatrix;
|
||||
m.postScale(1, -1);
|
||||
if (!m.invert(&fLocalMatrix)) {
|
||||
SkDebugf("Not invertible!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fGlyphCache = fSkPaint.detachCache(&fSurfaceProps, &fContextInitialMatrix,
|
||||
true /*ignoreGamma*/);
|
||||
fGlyphs = get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
|
||||
fGlyphCache = fSkPaint.detachCache(&fSurfaceProps, nullptr, true /*ignoreGamma*/);
|
||||
fGlyphs = canUseRawPaths ?
|
||||
get_gr_glyphs(fContext, fSkPaint.getTypeface(), nullptr, fStroke) :
|
||||
get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
|
||||
&fGlyphCache->getDescriptor(), fStroke);
|
||||
} else {
|
||||
// Don't bake strokes into the glyph outlines. We will stroke the glyphs
|
||||
// using the GPU instead. This is the fast path.
|
||||
fStroke = GrStrokeInfo(fSkPaint);
|
||||
fSkPaint.setStyle(SkPaint::kFill_Style);
|
||||
|
||||
if (fStroke.isHairlineStyle()) {
|
||||
// Approximate hairline stroke.
|
||||
SkScalar strokeWidth = SK_Scalar1 /
|
||||
(SkVector::Make(fContextInitialMatrix.getScaleX(),
|
||||
fContextInitialMatrix.getSkewY()).length());
|
||||
fStroke.setStrokeStyle(strokeWidth, false /*strokeAndFill*/);
|
||||
|
||||
} else if (fSkPaint.isFakeBoldText() &&
|
||||
#ifdef SK_USE_FREETYPE_EMBOLDEN
|
||||
kMaxPerformance_RenderMode == renderMode &&
|
||||
#endif
|
||||
SkStrokeRec::kStroke_Style != fStroke.getStyle()) {
|
||||
|
||||
// Instead of baking fake bold into the glyph outlines, do it with the GPU stroke.
|
||||
SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(),
|
||||
kStdFakeBoldInterpKeys,
|
||||
kStdFakeBoldInterpValues,
|
||||
kStdFakeBoldInterpLength);
|
||||
SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale);
|
||||
fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extra : extra,
|
||||
true /*strokeAndFill*/);
|
||||
|
||||
fSkPaint.setFakeBoldText(false);
|
||||
}
|
||||
|
||||
bool canUseRawPaths;
|
||||
if (!fStroke.isDashed() && (otherBackendsWillDrawAsPaths ||
|
||||
kMaxPerformance_RenderMode == renderMode)) {
|
||||
// We can draw the glyphs from canonically sized paths.
|
||||
fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
|
||||
fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.getTextSize();
|
||||
|
||||
// Compensate for the glyphs being scaled by fTextRatio.
|
||||
if (!fStroke.isFillStyle()) {
|
||||
fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio,
|
||||
SkStrokeRec::kStrokeAndFill_Style == fStroke.getStyle());
|
||||
}
|
||||
|
||||
fSkPaint.setLinearText(true);
|
||||
fSkPaint.setLCDRenderText(false);
|
||||
fSkPaint.setAutohinted(false);
|
||||
fSkPaint.setHinting(SkPaint::kNo_Hinting);
|
||||
fSkPaint.setSubpixelText(true);
|
||||
fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
|
||||
|
||||
canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() &&
|
||||
0 == fSkPaint.getTextSkewX() &&
|
||||
!fSkPaint.isFakeBoldText() &&
|
||||
!fSkPaint.isVerticalText();
|
||||
} else {
|
||||
fTextRatio = fTextInverseRatio = 1.0f;
|
||||
canUseRawPaths = false;
|
||||
}
|
||||
|
||||
SkMatrix textMatrix;
|
||||
// Glyphs loaded by GPU path rendering have an inverted y-direction.
|
||||
textMatrix.setScale(fTextRatio, -fTextRatio);
|
||||
fViewMatrix.preConcat(textMatrix);
|
||||
fLocalMatrix = textMatrix;
|
||||
|
||||
fGlyphCache = fSkPaint.detachCache(&fSurfaceProps, nullptr, true /*ignoreGamma*/);
|
||||
fGlyphs = canUseRawPaths ?
|
||||
get_gr_glyphs(fContext, fSkPaint.getTypeface(), nullptr, fStroke) :
|
||||
get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
|
||||
&fGlyphCache->getDescriptor(), fStroke);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool GrStencilAndCoverTextContext::mapToFallbackContext(SkMatrix* inverse) {
|
||||
// The current view matrix is flipped because GPU path rendering glyphs have an
|
||||
// inverted y-direction. Unflip the view matrix for the fallback context. If using
|
||||
// device-space glyphs, we'll also need to restore the original view matrix since
|
||||
// we moved that transfomation into our local glyph cache for this scenario. Also
|
||||
// track the inverse operation so the caller can unmap the paint and glyph positions.
|
||||
if (fUsingDeviceSpaceGlyphs) {
|
||||
fViewMatrix = fContextInitialMatrix;
|
||||
if (!fContextInitialMatrix.invert(inverse)) {
|
||||
return false;
|
||||
}
|
||||
inverse->preScale(1, -1);
|
||||
} else {
|
||||
inverse->setScale(1, -1);
|
||||
const SkMatrix& unflip = *inverse; // unflip is equal to its own inverse.
|
||||
fViewMatrix.preConcat(unflip);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, const SkPoint& pos) {
|
||||
// Stick the glyphs we can't draw into the fallback arrays.
|
||||
if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
|
||||
fFallbackIndices.push_back(glyph.getGlyphID());
|
||||
fFallbackPositions.push_back().set(fTextInverseRatio * pos.x(),
|
||||
-fTextInverseRatio * pos.y());
|
||||
fFallbackPositions.push_back(pos);
|
||||
} else {
|
||||
// TODO: infer the reserve count from the text length.
|
||||
if (!fDraw) {
|
||||
@ -412,18 +290,11 @@ inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, cons
|
||||
GrPathRendering::kTranslate_PathTransformType,
|
||||
64);
|
||||
}
|
||||
float translate[] = { fTextInverseRatio * pos.x(), -fTextInverseRatio * pos.y() };
|
||||
float translate[] = { fTextInverseRatio * pos.x(), fTextInverseRatio * pos.y() };
|
||||
fDraw->append(glyph.getGlyphID(), translate);
|
||||
}
|
||||
}
|
||||
|
||||
static const SkScalar* get_xy_scalar_array(const SkPoint* pointArray) {
|
||||
GR_STATIC_ASSERT(2 * sizeof(SkScalar) == sizeof(SkPoint));
|
||||
GR_STATIC_ASSERT(0 == offsetof(SkPoint, fX));
|
||||
|
||||
return &pointArray[0].fX;
|
||||
}
|
||||
|
||||
void GrStencilAndCoverTextContext::flush(GrDrawContext* dc) {
|
||||
if (fDraw) {
|
||||
SkASSERT(fDraw->count());
|
||||
@ -452,25 +323,27 @@ void GrStencilAndCoverTextContext::flush(GrDrawContext* dc) {
|
||||
|
||||
if (fFallbackIndices.count()) {
|
||||
SkASSERT(fFallbackPositions.count() == fFallbackIndices.count());
|
||||
GrPaint paintFallback(fPaint);
|
||||
|
||||
SkPaint skPaintFallback(fSkPaint);
|
||||
if (!fUsingDeviceSpaceGlyphs) {
|
||||
fStroke.applyToPaint(&skPaintFallback);
|
||||
SkPaint fallbackSkPaint(fSkPaint);
|
||||
fStroke.applyToPaint(&fallbackSkPaint);
|
||||
if (!fStroke.isFillStyle()) {
|
||||
fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio);
|
||||
}
|
||||
skPaintFallback.setTextAlign(SkPaint::kLeft_Align); // Align has already been accounted for.
|
||||
skPaintFallback.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
|
||||
fallbackSkPaint.setTextAlign(SkPaint::kLeft_Align); // Align has already been accounted for.
|
||||
fallbackSkPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
|
||||
// No need for subpixel positioning with bitmap glyphs. TODO: revisit if non-bitmap color
|
||||
// glyphs show up and https://code.google.com/p/skia/issues/detail?id=4408 gets resolved.
|
||||
fallbackSkPaint.setSubpixelText(false);
|
||||
fallbackSkPaint.setTextSize(fSkPaint.getTextSize() * fTextRatio);
|
||||
|
||||
SkMatrix inverse;
|
||||
if (this->mapToFallbackContext(&inverse)) {
|
||||
inverse.mapPoints(fFallbackPositions.begin(), fFallbackPositions.count());
|
||||
}
|
||||
SkMatrix fallbackMatrix(fViewMatrix);
|
||||
fallbackMatrix.preScale(fTextInverseRatio, fTextInverseRatio);
|
||||
|
||||
fFallbackTextContext->drawPosText(dc, fRenderTarget, fClip, paintFallback, skPaintFallback,
|
||||
fViewMatrix, (char*)fFallbackIndices.begin(),
|
||||
fFallbackTextContext->drawPosText(dc, fRenderTarget, fClip, fPaint, fallbackSkPaint,
|
||||
fallbackMatrix, (char*)fFallbackIndices.begin(),
|
||||
sizeof(uint16_t) * fFallbackIndices.count(),
|
||||
get_xy_scalar_array(fFallbackPositions.begin()),
|
||||
2, SkPoint::Make(0, 0), fRegionClipBounds);
|
||||
fFallbackPositions[0].asScalars(), 2, SkPoint::Make(0, 0),
|
||||
fRegionClipBounds);
|
||||
fFallbackIndices.reset();
|
||||
fFallbackPositions.reset();
|
||||
}
|
||||
@ -488,6 +361,4 @@ void GrStencilAndCoverTextContext::finish(GrDrawContext* dc) {
|
||||
|
||||
SkGlyphCache::AttachCache(fGlyphCache);
|
||||
fGlyphCache = nullptr;
|
||||
|
||||
fViewMatrix = fContextInitialMatrix;
|
||||
}
|
||||
|
@ -30,27 +30,6 @@ public:
|
||||
virtual ~GrStencilAndCoverTextContext();
|
||||
|
||||
private:
|
||||
enum RenderMode {
|
||||
/**
|
||||
* This is the render mode used by drawText(), which is mainly used by
|
||||
* the Skia unit tests. It tries match the other text backends exactly,
|
||||
* with the exception of not implementing LCD text, and doing anti-
|
||||
* aliasing with the built-in MSAA.
|
||||
*/
|
||||
kMaxAccuracy_RenderMode,
|
||||
|
||||
/**
|
||||
* This is the render mode used by drawPosText(). It ignores hinting and
|
||||
* LCD text, even if the client provided positions for hinted glyphs,
|
||||
* and renders from a canonically-sized, generic set of paths for the
|
||||
* given typeface. In the future we should work out a system for the
|
||||
* client to know it should not provide hinted glyph positions. This
|
||||
* render mode also tries to use GPU stroking for fake bold, even when
|
||||
* SK_USE_FREETYPE_EMBOLDEN is set.
|
||||
*/
|
||||
kMaxPerformance_RenderMode,
|
||||
};
|
||||
|
||||
SkScalar fTextRatio;
|
||||
float fTextInverseRatio;
|
||||
SkGlyphCache* fGlyphCache;
|
||||
@ -61,10 +40,8 @@ private:
|
||||
SkSTArray<32, uint16_t, true> fFallbackIndices;
|
||||
SkSTArray<32, SkPoint, true> fFallbackPositions;
|
||||
|
||||
SkMatrix fContextInitialMatrix;
|
||||
SkMatrix fViewMatrix;
|
||||
SkMatrix fLocalMatrix;
|
||||
bool fUsingDeviceSpaceGlyphs;
|
||||
SkAutoTUnref<GrRenderTarget> fRenderTarget;
|
||||
GrClip fClip;
|
||||
SkIRect fClipRect;
|
||||
@ -88,10 +65,8 @@ private:
|
||||
const SkScalar pos[], int scalarsPerPosition,
|
||||
const SkPoint& offset, const SkIRect& regionClipBounds) override;
|
||||
|
||||
void init(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&,
|
||||
size_t textByteLength, RenderMode, const SkMatrix& viewMatrix,
|
||||
const SkIRect& regionClipBounds);
|
||||
bool mapToFallbackContext(SkMatrix* inverse);
|
||||
void init(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&, size_t textByteLength,
|
||||
const SkMatrix& viewMatrix, const SkIRect& regionClipBounds);
|
||||
void appendGlyph(const SkGlyph&, const SkPoint&);
|
||||
void flush(GrDrawContext* dc);
|
||||
void finish(GrDrawContext* dc);
|
||||
|
Loading…
Reference in New Issue
Block a user