diff options
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrPathRendering.cpp | 6 | ||||
-rw-r--r-- | src/gpu/GrStencilAndCoverTextContext.cpp | 267 | ||||
-rw-r--r-- | src/gpu/GrStencilAndCoverTextContext.h | 29 |
3 files changed, 72 insertions, 230 deletions
diff --git a/src/gpu/GrPathRendering.cpp b/src/gpu/GrPathRendering.cpp index d98d9d2f30..0287eb08aa 100644 --- a/src/gpu/GrPathRendering.cpp +++ b/src/gpu/GrPathRendering.cpp @@ -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 diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp index fbd32fc856..9c0fc2a8ec 100644 --- a/src/gpu/GrStencilAndCoverTextContext.cpp +++ b/src/gpu/GrStencilAndCoverTextContext.cpp @@ -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(); - - const bool otherBackendsWillDrawAsPaths = - SkDraw::ShouldDrawTextAsPaths(skPaint, fContextInitialMatrix); + // 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); - fUsingDeviceSpaceGlyphs = !otherBackendsWillDrawAsPaths && - kMaxAccuracy_RenderMode == renderMode && - SkToBool(fContextInitialMatrix.getType() & - (SkMatrix::kScale_Mask | SkMatrix::kAffine_Mask)); + SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported. - if (fUsingDeviceSpaceGlyphs) { - // SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms. - SkASSERT(!fContextInitialMatrix.hasPerspective()); + 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*/); - // The whole shape (including stroke) will be baked into the glyph outlines. Make - // NVPR just fill the baked shapes. - fStroke = GrStrokeInfo(SkStrokeRec::kFill_InitStyle); + fSkPaint.setFakeBoldText(false); + } - fTextRatio = fTextInverseRatio = 1.0f; + bool canUseRawPaths; + if (!fStroke.isDashed()) { + // We can draw the glyphs from canonically sized paths. + fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths; + fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.getTextSize(); - // Glyphs loaded by GPU path rendering have an inverted y-direction. - SkMatrix m; - m.setScale(1, -1); - fViewMatrix = m; - - // 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; + // Compensate for the glyphs being scaled by fTextRatio. + if (!fStroke.isFillStyle()) { + fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio, + SkStrokeRec::kStrokeAndFill_Style == fStroke.getStyle()); } - fGlyphCache = fSkPaint.detachCache(&fSurfaceProps, &fContextInitialMatrix, - true /*ignoreGamma*/); - fGlyphs = get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(), - &fGlyphCache->getDescriptor(), fStroke); + 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 { - // 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); + fTextRatio = fTextInverseRatio = 1.0f; + canUseRawPaths = false; } -} + fViewMatrix = viewMatrix; + fViewMatrix.preScale(fTextRatio, fTextRatio); + fLocalMatrix.setScale(fTextRatio, fTextRatio); -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; + 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); } 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); - - SkMatrix inverse; - if (this->mapToFallbackContext(&inverse)) { - inverse.mapPoints(fFallbackPositions.begin(), fFallbackPositions.count()); - } - - fFallbackTextContext->drawPosText(dc, fRenderTarget, fClip, paintFallback, skPaintFallback, - fViewMatrix, (char*)fFallbackIndices.begin(), + 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 fallbackMatrix(fViewMatrix); + fallbackMatrix.preScale(fTextInverseRatio, fTextInverseRatio); + + 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; } diff --git a/src/gpu/GrStencilAndCoverTextContext.h b/src/gpu/GrStencilAndCoverTextContext.h index 4c57d3cb81..44b33a593d 100644 --- a/src/gpu/GrStencilAndCoverTextContext.h +++ b/src/gpu/GrStencilAndCoverTextContext.h @@ -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); |