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