1 /*
2 * Copyright 2017 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 "SkAtlasTextTarget.h"
9
10 #include "GrClip.h"
11 #include "GrContextPriv.h"
12 #include "GrDrawingManager.h"
13 #include "GrMemoryPool.h"
14 #include "SkAtlasTextContext.h"
15 #include "SkAtlasTextFont.h"
16 #include "SkAtlasTextRenderer.h"
17 #include "SkGlyphRunPainter.h"
18 #include "SkGr.h"
19 #include "SkInternalAtlasTextContext.h"
20 #include "ops/GrAtlasTextOp.h"
21 #include "text/GrTextContext.h"
22
23 static constexpr int kMaxBatchLookBack = 10;
24
SkAtlasTextTarget(sk_sp<SkAtlasTextContext> context,int width,int height,void * handle)25 SkAtlasTextTarget::SkAtlasTextTarget(sk_sp<SkAtlasTextContext> context, int width, int height,
26 void* handle)
27 : fHandle(handle)
28 , fContext(std::move(context))
29 , fWidth(width)
30 , fHeight(height)
31 , fMatrixStack(sizeof(SkMatrix), 4)
32 , fSaveCnt(0) {
33 fMatrixStack.push_back();
34 this->accessCTM()->reset();
35 }
36
~SkAtlasTextTarget()37 SkAtlasTextTarget::~SkAtlasTextTarget() { fContext->renderer()->targetDeleted(fHandle); }
38
save()39 int SkAtlasTextTarget::save() {
40 const auto& currCTM = this->ctm();
41 *static_cast<SkMatrix*>(fMatrixStack.push_back()) = currCTM;
42 return fSaveCnt++;
43 }
44
restore()45 void SkAtlasTextTarget::restore() {
46 if (fSaveCnt) {
47 fMatrixStack.pop_back();
48 fSaveCnt--;
49 }
50 }
51
restoreToCount(int count)52 void SkAtlasTextTarget::restoreToCount(int count) {
53 while (fSaveCnt > count) {
54 this->restore();
55 }
56 }
57
translate(SkScalar dx,SkScalar dy)58 void SkAtlasTextTarget::translate(SkScalar dx, SkScalar dy) {
59 this->accessCTM()->preTranslate(dx, dy);
60 }
61
scale(SkScalar sx,SkScalar sy)62 void SkAtlasTextTarget::scale(SkScalar sx, SkScalar sy) { this->accessCTM()->preScale(sx, sy); }
63
rotate(SkScalar degrees)64 void SkAtlasTextTarget::rotate(SkScalar degrees) { this->accessCTM()->preRotate(degrees); }
65
rotate(SkScalar degrees,SkScalar px,SkScalar py)66 void SkAtlasTextTarget::rotate(SkScalar degrees, SkScalar px, SkScalar py) {
67 this->accessCTM()->preRotate(degrees, px, py);
68 }
69
skew(SkScalar sx,SkScalar sy)70 void SkAtlasTextTarget::skew(SkScalar sx, SkScalar sy) { this->accessCTM()->preSkew(sx, sy); }
71
concat(const SkMatrix & matrix)72 void SkAtlasTextTarget::concat(const SkMatrix& matrix) { this->accessCTM()->preConcat(matrix); }
73
74 //////////////////////////////////////////////////////////////////////////////
75
76 static const GrColorSpaceInfo kColorSpaceInfo(nullptr, kRGBA_8888_GrPixelConfig);
77 static const SkSurfaceProps kProps(
78 SkSurfaceProps::kUseDistanceFieldFonts_Flag, kUnknown_SkPixelGeometry);
79
80 //////////////////////////////////////////////////////////////////////////////
81
82 class SkInternalAtlasTextTarget : public GrTextTarget, public SkAtlasTextTarget {
83 public:
SkInternalAtlasTextTarget(sk_sp<SkAtlasTextContext> context,int width,int height,void * handle)84 SkInternalAtlasTextTarget(sk_sp<SkAtlasTextContext> context,
85 int width, int height,
86 void* handle)
87 : GrTextTarget(width, height, kColorSpaceInfo)
88 , SkAtlasTextTarget(std::move(context), width, height, handle)
89 , fGlyphPainter(kProps, kColorSpaceInfo) {
90 fOpMemoryPool = fContext->internal().grContext()->contextPriv().refOpMemoryPool();
91 }
92
~SkInternalAtlasTextTarget()93 ~SkInternalAtlasTextTarget() override {
94 this->deleteOps();
95 }
96
97 /** GrTextTarget overrides */
98
99 void addDrawOp(const GrClip&, std::unique_ptr<GrAtlasTextOp> op) override;
100
drawShape(const GrClip &,const SkPaint &,const SkMatrix & viewMatrix,const GrShape &)101 void drawShape(const GrClip&, const SkPaint&, const SkMatrix& viewMatrix,
102 const GrShape&) override {
103 SkDebugf("Path glyph??");
104 }
105
makeGrPaint(GrMaskFormat,const SkPaint & skPaint,const SkMatrix &,GrPaint * grPaint)106 void makeGrPaint(GrMaskFormat, const SkPaint& skPaint, const SkMatrix&,
107 GrPaint* grPaint) override {
108 grPaint->setColor4f(skPaint.getColor4f().premul());
109 }
110
getContext()111 GrContext* getContext() override {
112 return this->context()->internal().grContext();
113 }
114
glyphPainter()115 SkGlyphRunListPainter* glyphPainter() override {
116 return &fGlyphPainter;
117 }
118
119 /** SkAtlasTextTarget overrides */
120
121 void drawText(const SkGlyphID[], const SkPoint[], int glyphCnt, uint32_t color,
122 const SkAtlasTextFont&) override;
123 void flush() override;
124
125 private:
126 void deleteOps();
127
128 uint32_t fColor;
129 using SkAtlasTextTarget::fWidth;
130 using SkAtlasTextTarget::fHeight;
131 SkTArray<std::unique_ptr<GrAtlasTextOp>, true> fOps;
132 sk_sp<GrOpMemoryPool> fOpMemoryPool;
133 SkGlyphRunListPainter fGlyphPainter;
134 };
135
136 //////////////////////////////////////////////////////////////////////////////
137
Make(sk_sp<SkAtlasTextContext> context,int width,int height,void * handle)138 std::unique_ptr<SkAtlasTextTarget> SkAtlasTextTarget::Make(sk_sp<SkAtlasTextContext> context,
139 int width, int height, void* handle) {
140 return std::unique_ptr<SkAtlasTextTarget>(
141 new SkInternalAtlasTextTarget(std::move(context), width, height, handle));
142 }
143
144 //////////////////////////////////////////////////////////////////////////////
145
drawText(const SkGlyphID glyphs[],const SkPoint positions[],int glyphCnt,uint32_t color,const SkAtlasTextFont & font)146 void SkInternalAtlasTextTarget::drawText(const SkGlyphID glyphs[], const SkPoint positions[],
147 int glyphCnt, uint32_t color,
148 const SkAtlasTextFont& font) {
149 SkPaint paint;
150 paint.setAntiAlias(true);
151
152 // The atlas text context does munging of the paint color. We store the client's color here
153 // and then overwrite the generated op's color when addDrawOp() is called.
154 fColor = color;
155
156 SkSurfaceProps props(SkSurfaceProps::kUseDistanceFieldFonts_Flag, kUnknown_SkPixelGeometry);
157 auto* grContext = this->context()->internal().grContext();
158 auto atlasTextContext = grContext->contextPriv().drawingManager()->getTextContext();
159 SkGlyphRunBuilder builder;
160 builder.drawGlyphsWithPositions(paint, font.makeFont(),
161 SkSpan<const SkGlyphID>{glyphs, SkTo<size_t>(glyphCnt)},
162 positions);
163 auto glyphRunList = builder.useGlyphRunList();
164 if (!glyphRunList.empty()) {
165 atlasTextContext->drawGlyphRunList(grContext, this, GrNoClip(), this->ctm(), props,
166 glyphRunList);
167 }
168 }
169
addDrawOp(const GrClip & clip,std::unique_ptr<GrAtlasTextOp> op)170 void SkInternalAtlasTextTarget::addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) {
171 SkASSERT(clip.quickContains(SkRect::MakeIWH(fWidth, fHeight)));
172 // The SkAtlasTextRenderer currently only handles grayscale SDF glyphs.
173 if (op->maskType() != GrAtlasTextOp::kGrayscaleDistanceField_MaskType) {
174 return;
175 }
176 const GrCaps& caps = *this->context()->internal().grContext()->contextPriv().caps();
177 op->finalizeForTextTarget(fColor, caps);
178 int n = SkTMin(kMaxBatchLookBack, fOps.count());
179 for (int i = 0; i < n; ++i) {
180 GrAtlasTextOp* other = fOps.fromBack(i).get();
181 if (other->combineIfPossible(op.get(), caps) == GrOp::CombineResult::kMerged) {
182 fOpMemoryPool->release(std::move(op));
183 return;
184 }
185 if (GrRectsOverlap(op->bounds(), other->bounds())) {
186 break;
187 }
188 }
189 fOps.emplace_back(std::move(op));
190 }
191
deleteOps()192 void SkInternalAtlasTextTarget::deleteOps() {
193 for (int i = 0; i < fOps.count(); ++i) {
194 if (fOps[i]) {
195 fOpMemoryPool->release(std::move(fOps[i]));
196 }
197 }
198 fOps.reset();
199 }
200
flush()201 void SkInternalAtlasTextTarget::flush() {
202 for (int i = 0; i < fOps.count(); ++i) {
203 fOps[i]->executeForTextTarget(this);
204 }
205 this->context()->internal().flush();
206 this->deleteOps();
207 }
208
finalizeForTextTarget(uint32_t color,const GrCaps & caps)209 void GrAtlasTextOp::finalizeForTextTarget(uint32_t color, const GrCaps& caps) {
210 // TODO4F: Odd handling of client colors among AtlasTextTarget and AtlasTextRenderer
211 SkPMColor4f color4f = SkPMColor4f::FromBytes_RGBA(color);
212 for (int i = 0; i < fGeoCount; ++i) {
213 fGeoData[i].fColor = color4f;
214 }
215 this->finalize(caps, nullptr /* applied clip */);
216 }
217
executeForTextTarget(SkAtlasTextTarget * target)218 void GrAtlasTextOp::executeForTextTarget(SkAtlasTextTarget* target) {
219 FlushInfo flushInfo;
220 SkExclusiveStrikePtr autoGlyphCache;
221 auto& context = target->context()->internal();
222 auto glyphCache = context.grContext()->contextPriv().getGlyphCache();
223 auto atlasManager = context.grContext()->contextPriv().getAtlasManager();
224 auto resourceProvider = context.grContext()->contextPriv().resourceProvider();
225
226 unsigned int numProxies;
227 if (!atlasManager->getProxies(kA8_GrMaskFormat, &numProxies)) {
228 return;
229 }
230
231 for (int i = 0; i < fGeoCount; ++i) {
232 // TODO4F: Preserve float colors
233 GrTextBlob::VertexRegenerator regenerator(
234 resourceProvider, fGeoData[i].fBlob, fGeoData[i].fRun, fGeoData[i].fSubRun,
235 fGeoData[i].fViewMatrix, fGeoData[i].fX, fGeoData[i].fY,
236 fGeoData[i].fColor.toBytes_RGBA(), &context, glyphCache, atlasManager,
237 &autoGlyphCache);
238 bool done = false;
239 while (!done) {
240 GrTextBlob::VertexRegenerator::Result result;
241 if (!regenerator.regenerate(&result)) {
242 break;
243 }
244 done = result.fFinished;
245
246 context.recordDraw(result.fFirstVertex, result.fGlyphsRegenerated,
247 fGeoData[i].fViewMatrix, target->handle());
248 if (!result.fFinished) {
249 // Make space in the atlas so we can continue generating vertices.
250 context.flush();
251 }
252 }
253 }
254 }
255