• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "GrTextUtils.h"
9 #include "GrContext.h"
10 #include "SkDrawFilter.h"
11 #include "SkDrawProcs.h"
12 #include "SkGlyphCache.h"
13 #include "SkGr.h"
14 #include "SkPaint.h"
15 #include "SkTextBlobRunIterator.h"
16 #include "SkTextMapStateProc.h"
17 #include "SkTextToPathIter.h"
18 
initFilteredColor()19 void GrTextUtils::Paint::initFilteredColor() {
20     // This mirrors the logic in skpaint_to_grpaint_impl for handling paint colors
21     if (fDstColorSpaceInfo->colorSpace()) {
22         GrColor4f filteredColor =
23                 SkColorToUnpremulGrColor4f(fPaint->getColor(), *fDstColorSpaceInfo);
24         if (fPaint->getColorFilter()) {
25             filteredColor = GrColor4f::FromSkColor4f(
26                 fPaint->getColorFilter()->filterColor4f(filteredColor.toSkColor4f()));
27         }
28         fFilteredPremulColor = filteredColor.premul().toGrColor();
29     } else {
30         SkColor filteredSkColor = fPaint->getColor();
31         if (fPaint->getColorFilter()) {
32             filteredSkColor = fPaint->getColorFilter()->filterColor(filteredSkColor);
33         }
34         fFilteredPremulColor = SkColorToPremulGrColor(filteredSkColor);
35     }
36 }
37 
modifyForRun(const SkTextBlobRunIterator & run)38 bool GrTextUtils::RunPaint::modifyForRun(const SkTextBlobRunIterator& run) {
39     if (!fModifiedPaint.isValid()) {
40         fModifiedPaint.init(fOriginalPaint->skPaint());
41         fPaint = fModifiedPaint.get();
42     } else if (fFilter) {
43         // We have to reset before applying the run because the filter could have arbitrary
44         // changed the paint.
45         *fModifiedPaint.get() = fOriginalPaint->skPaint();
46     }
47     run.applyFontToPaint(fModifiedPaint.get());
48 
49     if (fFilter) {
50         if (!fFilter->filter(fModifiedPaint.get(), SkDrawFilter::kText_Type)) {
51             // A false return from filter() means we should abort the current draw.
52             return false;
53         }
54         // The draw filter could have changed either the paint color or color filter.
55         this->initFilteredColor();
56     }
57     fModifiedPaint.get()->setFlags(FilterTextFlags(fProps, *fModifiedPaint.get()));
58     return true;
59 }
60 
FilterTextFlags(const SkSurfaceProps & surfaceProps,const SkPaint & paint)61 uint32_t GrTextUtils::FilterTextFlags(const SkSurfaceProps& surfaceProps, const SkPaint& paint) {
62     uint32_t flags = paint.getFlags();
63 
64     if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
65         return flags;
66     }
67 
68     if (kUnknown_SkPixelGeometry == surfaceProps.pixelGeometry() || ShouldDisableLCD(paint)) {
69         flags &= ~SkPaint::kLCDRenderText_Flag;
70         flags |= SkPaint::kGenA8FromLCD_Flag;
71     }
72 
73     return flags;
74 }
75 
ShouldDisableLCD(const SkPaint & paint)76 bool GrTextUtils::ShouldDisableLCD(const SkPaint& paint) {
77     return paint.getMaskFilter() || paint.getPathEffect() ||
78            paint.isFakeBoldText() || paint.getStyle() != SkPaint::kFill_Style;
79 }
80 
DrawBigText(GrTextUtils::Target * target,const GrClip & clip,const SkPaint & paint,const SkMatrix & viewMatrix,const char text[],size_t byteLength,SkScalar x,SkScalar y,const SkIRect & clipBounds)81 void GrTextUtils::DrawBigText(GrTextUtils::Target* target,
82                               const GrClip& clip, const SkPaint& paint,
83                               const SkMatrix& viewMatrix, const char text[], size_t byteLength,
84                               SkScalar x, SkScalar y, const SkIRect& clipBounds) {
85     if (!paint.countText(text, byteLength)) {
86         return;
87     }
88     SkTextToPathIter iter(text, byteLength, paint, true);
89 
90     SkMatrix    matrix;
91     matrix.setScale(iter.getPathScale(), iter.getPathScale());
92     matrix.postTranslate(x, y);
93 
94     const SkPath* iterPath;
95     SkScalar xpos, prevXPos = 0;
96 
97     while (iter.next(&iterPath, &xpos)) {
98         matrix.postTranslate(xpos - prevXPos, 0);
99         if (iterPath) {
100             const SkPaint& pnt = iter.getPaint();
101             target->drawPath(clip, *iterPath, pnt, viewMatrix, &matrix, clipBounds);
102         }
103         prevXPos = xpos;
104     }
105 }
106 
DrawBigPosText(GrTextUtils::Target * target,const SkSurfaceProps & props,const GrClip & clip,const SkPaint & origPaint,const SkMatrix & viewMatrix,const char text[],size_t byteLength,const SkScalar pos[],int scalarsPerPosition,const SkPoint & offset,const SkIRect & clipBounds)107 void GrTextUtils::DrawBigPosText(GrTextUtils::Target* target,
108                                  const SkSurfaceProps& props, const GrClip& clip,
109                                  const SkPaint& origPaint, const SkMatrix& viewMatrix,
110                                  const char text[], size_t byteLength, const SkScalar pos[],
111                                  int scalarsPerPosition, const SkPoint& offset,
112                                  const SkIRect& clipBounds) {
113     if (!origPaint.countText(text, byteLength)) {
114         return;
115     }
116     // setup our std paint, in hopes of getting hits in the cache
117     SkPaint paint(origPaint);
118     SkScalar matrixScale = paint.setupForAsPaths();
119 
120     SkMatrix matrix;
121     matrix.setScale(matrixScale, matrixScale);
122 
123     // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
124     paint.setStyle(SkPaint::kFill_Style);
125     paint.setPathEffect(nullptr);
126 
127     SkPaint::GlyphCacheProc    glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(),
128                                                                            paint.isDevKernText(),
129                                                                            true);
130     SkAutoGlyphCache           autoCache(paint, &props, nullptr);
131     SkGlyphCache*              cache = autoCache.getCache();
132 
133     const char*        stop = text + byteLength;
134     SkTextAlignProc    alignProc(paint.getTextAlign());
135     SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
136 
137     // Now restore the original settings, so we "draw" with whatever style/stroking.
138     paint.setStyle(origPaint.getStyle());
139     paint.setPathEffect(origPaint.refPathEffect());
140 
141     while (text < stop) {
142         const SkGlyph& glyph = glyphCacheProc(cache, &text);
143         if (glyph.fWidth) {
144             const SkPath* path = cache->findPath(glyph);
145             if (path) {
146                 SkPoint tmsLoc;
147                 tmsProc(pos, &tmsLoc);
148                 SkPoint loc;
149                 alignProc(tmsLoc, glyph, &loc);
150 
151                 matrix[SkMatrix::kMTransX] = loc.fX;
152                 matrix[SkMatrix::kMTransY] = loc.fY;
153                 target->drawPath(clip, *path, paint, viewMatrix, &matrix, clipBounds);
154             }
155         }
156         pos += scalarsPerPosition;
157     }
158 }
159