1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2022 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/text/gpu/SubRunContainer.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkDrawable.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMaskFilter.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathEffect.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStrokeRec.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurfaceProps.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkDashPathEffect.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkFloatingPoint.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkOnce.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTLogic.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkZip.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkDevice.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkDistanceFieldGen.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkEnumerate.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkFontPriv.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkGlyph.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMask.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMaskFilterBase.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMatrixPriv.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkPathEffectBase.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkReadBuffer.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkScalerContext.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkStrike.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkStrikeCache.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkStrikeSpec.h"
45*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkWriteBuffer.h"
46*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/AtlasTypes.h"
47*c8dee2aaSAndroid Build Coastguard Worker #include "src/text/GlyphRun.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "src/text/StrikeForGPU.h"
49*c8dee2aaSAndroid Build Coastguard Worker #include "src/text/gpu/Glyph.h"
50*c8dee2aaSAndroid Build Coastguard Worker #include "src/text/gpu/GlyphVector.h"
51*c8dee2aaSAndroid Build Coastguard Worker #include "src/text/gpu/SDFMaskFilter.h"
52*c8dee2aaSAndroid Build Coastguard Worker #include "src/text/gpu/SubRunAllocator.h"
53*c8dee2aaSAndroid Build Coastguard Worker #include "src/text/gpu/SubRunControl.h"
54*c8dee2aaSAndroid Build Coastguard Worker #include "src/text/gpu/VertexFiller.h"
55*c8dee2aaSAndroid Build Coastguard Worker
56*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
57*c8dee2aaSAndroid Build Coastguard Worker #include <climits>
58*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
59*c8dee2aaSAndroid Build Coastguard Worker #include <new>
60*c8dee2aaSAndroid Build Coastguard Worker #include <optional>
61*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
62*c8dee2aaSAndroid Build Coastguard Worker
63*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
64*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRRect.h"
65*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkColorData.h"
66*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
67*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkPaintPriv.h"
68*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrClip.h"
69*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrColorInfo.h"
70*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrFragmentProcessor.h"
71*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPaint.h"
72*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/SkGr.h"
73*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/SurfaceDrawContext.h"
74*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrDistanceFieldGeoProc.h"
75*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/AtlasTextOp.h"
76*c8dee2aaSAndroid Build Coastguard Worker
77*c8dee2aaSAndroid Build Coastguard Worker class GrRecordingContext;
78*c8dee2aaSAndroid Build Coastguard Worker
79*c8dee2aaSAndroid Build Coastguard Worker using AtlasTextOp = skgpu::ganesh::AtlasTextOp;
80*c8dee2aaSAndroid Build Coastguard Worker #endif // defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
81*c8dee2aaSAndroid Build Coastguard Worker
82*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
83*c8dee2aaSAndroid Build Coastguard Worker using namespace skglyph;
84*c8dee2aaSAndroid Build Coastguard Worker
85*c8dee2aaSAndroid Build Coastguard Worker // -- GPU Text -------------------------------------------------------------------------------------
86*c8dee2aaSAndroid Build Coastguard Worker // Naming conventions
87*c8dee2aaSAndroid Build Coastguard Worker // * drawMatrix - the CTM from the canvas.
88*c8dee2aaSAndroid Build Coastguard Worker // * drawOrigin - the x, y location of the drawTextBlob call.
89*c8dee2aaSAndroid Build Coastguard Worker // * positionMatrix - this is the combination of the drawMatrix and the drawOrigin:
90*c8dee2aaSAndroid Build Coastguard Worker // positionMatrix = drawMatrix * TranslationMatrix(drawOrigin.x, drawOrigin.y);
91*c8dee2aaSAndroid Build Coastguard Worker //
92*c8dee2aaSAndroid Build Coastguard Worker // Note:
93*c8dee2aaSAndroid Build Coastguard Worker // In order to transform Slugs, you need to set the fSupportBilerpFromGlyphAtlas on
94*c8dee2aaSAndroid Build Coastguard Worker // GrContextOptions.
95*c8dee2aaSAndroid Build Coastguard Worker
96*c8dee2aaSAndroid Build Coastguard Worker namespace sktext::gpu {
97*c8dee2aaSAndroid Build Coastguard Worker // -- SubRunStreamTag ------------------------------------------------------------------------------
98*c8dee2aaSAndroid Build Coastguard Worker enum SubRun::SubRunStreamTag : int {
99*c8dee2aaSAndroid Build Coastguard Worker kBad = 0, // Make this 0 to line up with errors from readInt.
100*c8dee2aaSAndroid Build Coastguard Worker kDirectMaskStreamTag,
101*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_DISABLE_SDF_TEXT)
102*c8dee2aaSAndroid Build Coastguard Worker kSDFTStreamTag,
103*c8dee2aaSAndroid Build Coastguard Worker #endif
104*c8dee2aaSAndroid Build Coastguard Worker kTransformMaskStreamTag,
105*c8dee2aaSAndroid Build Coastguard Worker kPathStreamTag,
106*c8dee2aaSAndroid Build Coastguard Worker kDrawableStreamTag,
107*c8dee2aaSAndroid Build Coastguard Worker kSubRunStreamTagCount,
108*c8dee2aaSAndroid Build Coastguard Worker };
109*c8dee2aaSAndroid Build Coastguard Worker
110*c8dee2aaSAndroid Build Coastguard Worker } // namespace sktext::gpu
111*c8dee2aaSAndroid Build Coastguard Worker
112*c8dee2aaSAndroid Build Coastguard Worker using MaskFormat = skgpu::MaskFormat;
113*c8dee2aaSAndroid Build Coastguard Worker
114*c8dee2aaSAndroid Build Coastguard Worker using namespace sktext;
115*c8dee2aaSAndroid Build Coastguard Worker using namespace sktext::gpu;
116*c8dee2aaSAndroid Build Coastguard Worker
117*c8dee2aaSAndroid Build Coastguard Worker namespace {
118*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
calculate_colors(skgpu::ganesh::SurfaceDrawContext * sdc,const SkPaint & paint,const SkMatrix & matrix,MaskFormat maskFormat,GrPaint * grPaint)119*c8dee2aaSAndroid Build Coastguard Worker SkPMColor4f calculate_colors(skgpu::ganesh::SurfaceDrawContext* sdc,
120*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint,
121*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& matrix,
122*c8dee2aaSAndroid Build Coastguard Worker MaskFormat maskFormat,
123*c8dee2aaSAndroid Build Coastguard Worker GrPaint* grPaint) {
124*c8dee2aaSAndroid Build Coastguard Worker GrRecordingContext* rContext = sdc->recordingContext();
125*c8dee2aaSAndroid Build Coastguard Worker const GrColorInfo& colorInfo = sdc->colorInfo();
126*c8dee2aaSAndroid Build Coastguard Worker const SkSurfaceProps& props = sdc->surfaceProps();
127*c8dee2aaSAndroid Build Coastguard Worker if (maskFormat == MaskFormat::kARGB) {
128*c8dee2aaSAndroid Build Coastguard Worker SkPaintToGrPaintReplaceShader(rContext, colorInfo, paint, matrix, nullptr, props, grPaint);
129*c8dee2aaSAndroid Build Coastguard Worker float a = grPaint->getColor4f().fA;
130*c8dee2aaSAndroid Build Coastguard Worker return {a, a, a, a};
131*c8dee2aaSAndroid Build Coastguard Worker }
132*c8dee2aaSAndroid Build Coastguard Worker SkPaintToGrPaint(rContext, colorInfo, paint, matrix, props, grPaint);
133*c8dee2aaSAndroid Build Coastguard Worker return grPaint->getColor4f();
134*c8dee2aaSAndroid Build Coastguard Worker }
135*c8dee2aaSAndroid Build Coastguard Worker
position_matrix(const SkMatrix & drawMatrix,SkPoint drawOrigin)136*c8dee2aaSAndroid Build Coastguard Worker SkMatrix position_matrix(const SkMatrix& drawMatrix, SkPoint drawOrigin) {
137*c8dee2aaSAndroid Build Coastguard Worker SkMatrix position_matrix = drawMatrix;
138*c8dee2aaSAndroid Build Coastguard Worker return position_matrix.preTranslate(drawOrigin.x(), drawOrigin.y());
139*c8dee2aaSAndroid Build Coastguard Worker }
140*c8dee2aaSAndroid Build Coastguard Worker #endif // defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
141*c8dee2aaSAndroid Build Coastguard Worker
get_packedIDs(SkZip<const SkPackedGlyphID,const SkPoint> accepted)142*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const SkPackedGlyphID> get_packedIDs(SkZip<const SkPackedGlyphID, const SkPoint> accepted) {
143*c8dee2aaSAndroid Build Coastguard Worker return accepted.get<0>();
144*c8dee2aaSAndroid Build Coastguard Worker }
145*c8dee2aaSAndroid Build Coastguard Worker
get_glyphIDs(SkZip<const SkGlyphID,const SkPoint> accepted)146*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const SkGlyphID> get_glyphIDs(SkZip<const SkGlyphID, const SkPoint> accepted) {
147*c8dee2aaSAndroid Build Coastguard Worker return accepted.get<0>();
148*c8dee2aaSAndroid Build Coastguard Worker }
149*c8dee2aaSAndroid Build Coastguard Worker
150*c8dee2aaSAndroid Build Coastguard Worker template <typename U>
get_positions(SkZip<U,const SkPoint> accepted)151*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const SkPoint> get_positions(SkZip<U, const SkPoint> accepted) {
152*c8dee2aaSAndroid Build Coastguard Worker return accepted.template get<1>();
153*c8dee2aaSAndroid Build Coastguard Worker }
154*c8dee2aaSAndroid Build Coastguard Worker
155*c8dee2aaSAndroid Build Coastguard Worker // -- PathOpSubmitter ------------------------------------------------------------------------------
156*c8dee2aaSAndroid Build Coastguard Worker // PathOpSubmitter holds glyph ids until ready to draw. During drawing, the glyph ids are
157*c8dee2aaSAndroid Build Coastguard Worker // converted to SkPaths. PathOpSubmitter can only be serialized when it is holding glyph ids;
158*c8dee2aaSAndroid Build Coastguard Worker // it can only be serialized before submitDraws has been called.
159*c8dee2aaSAndroid Build Coastguard Worker class PathOpSubmitter {
160*c8dee2aaSAndroid Build Coastguard Worker public:
161*c8dee2aaSAndroid Build Coastguard Worker PathOpSubmitter() = delete;
162*c8dee2aaSAndroid Build Coastguard Worker PathOpSubmitter(const PathOpSubmitter&) = delete;
163*c8dee2aaSAndroid Build Coastguard Worker const PathOpSubmitter& operator=(const PathOpSubmitter&) = delete;
PathOpSubmitter(PathOpSubmitter && that)164*c8dee2aaSAndroid Build Coastguard Worker PathOpSubmitter(PathOpSubmitter&& that)
165*c8dee2aaSAndroid Build Coastguard Worker // Transfer ownership of fIDsOrPaths from that to this.
166*c8dee2aaSAndroid Build Coastguard Worker : fIDsOrPaths{std::exchange(
167*c8dee2aaSAndroid Build Coastguard Worker const_cast<SkSpan<IDOrPath>&>(that.fIDsOrPaths), SkSpan<IDOrPath>{})}
168*c8dee2aaSAndroid Build Coastguard Worker , fPositions{that.fPositions}
169*c8dee2aaSAndroid Build Coastguard Worker , fStrikeToSourceScale{that.fStrikeToSourceScale}
170*c8dee2aaSAndroid Build Coastguard Worker , fIsAntiAliased{that.fIsAntiAliased}
171*c8dee2aaSAndroid Build Coastguard Worker , fStrikePromise{std::move(that.fStrikePromise)} {}
operator =(PathOpSubmitter && that)172*c8dee2aaSAndroid Build Coastguard Worker PathOpSubmitter& operator=(PathOpSubmitter&& that) {
173*c8dee2aaSAndroid Build Coastguard Worker this->~PathOpSubmitter();
174*c8dee2aaSAndroid Build Coastguard Worker new (this) PathOpSubmitter{std::move(that)};
175*c8dee2aaSAndroid Build Coastguard Worker return *this;
176*c8dee2aaSAndroid Build Coastguard Worker }
177*c8dee2aaSAndroid Build Coastguard Worker PathOpSubmitter(bool isAntiAliased,
178*c8dee2aaSAndroid Build Coastguard Worker SkScalar strikeToSourceScale,
179*c8dee2aaSAndroid Build Coastguard Worker SkSpan<SkPoint> positions,
180*c8dee2aaSAndroid Build Coastguard Worker SkSpan<IDOrPath> idsOrPaths,
181*c8dee2aaSAndroid Build Coastguard Worker SkStrikePromise&& strikePromise);
182*c8dee2aaSAndroid Build Coastguard Worker
183*c8dee2aaSAndroid Build Coastguard Worker ~PathOpSubmitter();
184*c8dee2aaSAndroid Build Coastguard Worker
185*c8dee2aaSAndroid Build Coastguard Worker static PathOpSubmitter Make(SkZip<const SkGlyphID, const SkPoint> accepted,
186*c8dee2aaSAndroid Build Coastguard Worker bool isAntiAliased,
187*c8dee2aaSAndroid Build Coastguard Worker SkScalar strikeToSourceScale,
188*c8dee2aaSAndroid Build Coastguard Worker SkStrikePromise&& strikePromise,
189*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc);
190*c8dee2aaSAndroid Build Coastguard Worker
191*c8dee2aaSAndroid Build Coastguard Worker int unflattenSize() const;
192*c8dee2aaSAndroid Build Coastguard Worker void flatten(SkWriteBuffer& buffer) const;
193*c8dee2aaSAndroid Build Coastguard Worker static std::optional<PathOpSubmitter> MakeFromBuffer(SkReadBuffer& buffer,
194*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc,
195*c8dee2aaSAndroid Build Coastguard Worker const SkStrikeClient* client);
196*c8dee2aaSAndroid Build Coastguard Worker
197*c8dee2aaSAndroid Build Coastguard Worker // submitDraws is not thread safe. It only occurs the single thread drawing portion of the GPU
198*c8dee2aaSAndroid Build Coastguard Worker // rendering.
199*c8dee2aaSAndroid Build Coastguard Worker void submitDraws(SkCanvas*,
200*c8dee2aaSAndroid Build Coastguard Worker SkPoint drawOrigin,
201*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint) const;
202*c8dee2aaSAndroid Build Coastguard Worker
203*c8dee2aaSAndroid Build Coastguard Worker private:
204*c8dee2aaSAndroid Build Coastguard Worker // When PathOpSubmitter is created only the glyphIDs are needed, during the submitDraws call,
205*c8dee2aaSAndroid Build Coastguard Worker // the glyphIDs are converted to SkPaths.
206*c8dee2aaSAndroid Build Coastguard Worker const SkSpan<IDOrPath> fIDsOrPaths;
207*c8dee2aaSAndroid Build Coastguard Worker const SkSpan<const SkPoint> fPositions;
208*c8dee2aaSAndroid Build Coastguard Worker const SkScalar fStrikeToSourceScale;
209*c8dee2aaSAndroid Build Coastguard Worker const bool fIsAntiAliased;
210*c8dee2aaSAndroid Build Coastguard Worker
211*c8dee2aaSAndroid Build Coastguard Worker mutable SkStrikePromise fStrikePromise;
212*c8dee2aaSAndroid Build Coastguard Worker mutable SkOnce fConvertIDsToPaths;
213*c8dee2aaSAndroid Build Coastguard Worker mutable bool fPathsAreCreated{false};
214*c8dee2aaSAndroid Build Coastguard Worker };
215*c8dee2aaSAndroid Build Coastguard Worker
unflattenSize() const216*c8dee2aaSAndroid Build Coastguard Worker int PathOpSubmitter::unflattenSize() const {
217*c8dee2aaSAndroid Build Coastguard Worker return fPositions.size_bytes() + fIDsOrPaths.size_bytes();
218*c8dee2aaSAndroid Build Coastguard Worker }
219*c8dee2aaSAndroid Build Coastguard Worker
flatten(SkWriteBuffer & buffer) const220*c8dee2aaSAndroid Build Coastguard Worker void PathOpSubmitter::flatten(SkWriteBuffer& buffer) const {
221*c8dee2aaSAndroid Build Coastguard Worker fStrikePromise.flatten(buffer);
222*c8dee2aaSAndroid Build Coastguard Worker
223*c8dee2aaSAndroid Build Coastguard Worker buffer.writeInt(fIsAntiAliased);
224*c8dee2aaSAndroid Build Coastguard Worker buffer.writeScalar(fStrikeToSourceScale);
225*c8dee2aaSAndroid Build Coastguard Worker buffer.writePointArray(fPositions.data(), SkCount(fPositions));
226*c8dee2aaSAndroid Build Coastguard Worker for (IDOrPath& idOrPath : fIDsOrPaths) {
227*c8dee2aaSAndroid Build Coastguard Worker buffer.writeInt(idOrPath.fGlyphID);
228*c8dee2aaSAndroid Build Coastguard Worker }
229*c8dee2aaSAndroid Build Coastguard Worker }
230*c8dee2aaSAndroid Build Coastguard Worker
MakeFromBuffer(SkReadBuffer & buffer,SubRunAllocator * alloc,const SkStrikeClient * client)231*c8dee2aaSAndroid Build Coastguard Worker std::optional<PathOpSubmitter> PathOpSubmitter::MakeFromBuffer(SkReadBuffer& buffer,
232*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc,
233*c8dee2aaSAndroid Build Coastguard Worker const SkStrikeClient* client) {
234*c8dee2aaSAndroid Build Coastguard Worker std::optional<SkStrikePromise> strikePromise =
235*c8dee2aaSAndroid Build Coastguard Worker SkStrikePromise::MakeFromBuffer(buffer, client, SkStrikeCache::GlobalStrikeCache());
236*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(strikePromise.has_value())) {
237*c8dee2aaSAndroid Build Coastguard Worker return std::nullopt;
238*c8dee2aaSAndroid Build Coastguard Worker }
239*c8dee2aaSAndroid Build Coastguard Worker
240*c8dee2aaSAndroid Build Coastguard Worker bool isAntiAlias = buffer.readInt();
241*c8dee2aaSAndroid Build Coastguard Worker
242*c8dee2aaSAndroid Build Coastguard Worker SkScalar strikeToSourceScale = buffer.readScalar();
243*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(0 < strikeToSourceScale)) { return std::nullopt; }
244*c8dee2aaSAndroid Build Coastguard Worker
245*c8dee2aaSAndroid Build Coastguard Worker SkSpan<SkPoint> positions = MakePointsFromBuffer(buffer, alloc);
246*c8dee2aaSAndroid Build Coastguard Worker if (positions.empty()) { return std::nullopt; }
247*c8dee2aaSAndroid Build Coastguard Worker const int glyphCount = SkCount(positions);
248*c8dee2aaSAndroid Build Coastguard Worker
249*c8dee2aaSAndroid Build Coastguard Worker // Remember, we stored an int for glyph id.
250*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validateCanReadN<int>(glyphCount)) { return std::nullopt; }
251*c8dee2aaSAndroid Build Coastguard Worker auto idsOrPaths = SkSpan(alloc->makeUniqueArray<IDOrPath>(glyphCount).release(), glyphCount);
252*c8dee2aaSAndroid Build Coastguard Worker for (auto& idOrPath : idsOrPaths) {
253*c8dee2aaSAndroid Build Coastguard Worker idOrPath.fGlyphID = SkTo<SkGlyphID>(buffer.readInt());
254*c8dee2aaSAndroid Build Coastguard Worker }
255*c8dee2aaSAndroid Build Coastguard Worker
256*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.isValid()) { return std::nullopt; }
257*c8dee2aaSAndroid Build Coastguard Worker
258*c8dee2aaSAndroid Build Coastguard Worker return PathOpSubmitter{isAntiAlias,
259*c8dee2aaSAndroid Build Coastguard Worker strikeToSourceScale,
260*c8dee2aaSAndroid Build Coastguard Worker positions,
261*c8dee2aaSAndroid Build Coastguard Worker idsOrPaths,
262*c8dee2aaSAndroid Build Coastguard Worker std::move(strikePromise.value())};
263*c8dee2aaSAndroid Build Coastguard Worker }
264*c8dee2aaSAndroid Build Coastguard Worker
PathOpSubmitter(bool isAntiAliased,SkScalar strikeToSourceScale,SkSpan<SkPoint> positions,SkSpan<IDOrPath> idsOrPaths,SkStrikePromise && strikePromise)265*c8dee2aaSAndroid Build Coastguard Worker PathOpSubmitter::PathOpSubmitter(
266*c8dee2aaSAndroid Build Coastguard Worker bool isAntiAliased,
267*c8dee2aaSAndroid Build Coastguard Worker SkScalar strikeToSourceScale,
268*c8dee2aaSAndroid Build Coastguard Worker SkSpan<SkPoint> positions,
269*c8dee2aaSAndroid Build Coastguard Worker SkSpan<IDOrPath> idsOrPaths,
270*c8dee2aaSAndroid Build Coastguard Worker SkStrikePromise&& strikePromise)
271*c8dee2aaSAndroid Build Coastguard Worker : fIDsOrPaths{idsOrPaths}
272*c8dee2aaSAndroid Build Coastguard Worker , fPositions{positions}
273*c8dee2aaSAndroid Build Coastguard Worker , fStrikeToSourceScale{strikeToSourceScale}
274*c8dee2aaSAndroid Build Coastguard Worker , fIsAntiAliased{isAntiAliased}
275*c8dee2aaSAndroid Build Coastguard Worker , fStrikePromise{std::move(strikePromise)} {
276*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fPositions.empty());
277*c8dee2aaSAndroid Build Coastguard Worker }
278*c8dee2aaSAndroid Build Coastguard Worker
~PathOpSubmitter()279*c8dee2aaSAndroid Build Coastguard Worker PathOpSubmitter::~PathOpSubmitter() {
280*c8dee2aaSAndroid Build Coastguard Worker // If we have converted glyph IDs to paths, then clean up the SkPaths.
281*c8dee2aaSAndroid Build Coastguard Worker if (fPathsAreCreated) {
282*c8dee2aaSAndroid Build Coastguard Worker for (auto& idOrPath : fIDsOrPaths) {
283*c8dee2aaSAndroid Build Coastguard Worker idOrPath.fPath.~SkPath();
284*c8dee2aaSAndroid Build Coastguard Worker }
285*c8dee2aaSAndroid Build Coastguard Worker }
286*c8dee2aaSAndroid Build Coastguard Worker }
287*c8dee2aaSAndroid Build Coastguard Worker
Make(SkZip<const SkGlyphID,const SkPoint> accepted,bool isAntiAliased,SkScalar strikeToSourceScale,SkStrikePromise && strikePromise,SubRunAllocator * alloc)288*c8dee2aaSAndroid Build Coastguard Worker PathOpSubmitter PathOpSubmitter::Make(SkZip<const SkGlyphID, const SkPoint> accepted,
289*c8dee2aaSAndroid Build Coastguard Worker bool isAntiAliased,
290*c8dee2aaSAndroid Build Coastguard Worker SkScalar strikeToSourceScale,
291*c8dee2aaSAndroid Build Coastguard Worker SkStrikePromise&& strikePromise,
292*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc) {
293*c8dee2aaSAndroid Build Coastguard Worker auto mapToIDOrPath = [](SkGlyphID glyphID) { return IDOrPath{glyphID}; };
294*c8dee2aaSAndroid Build Coastguard Worker
295*c8dee2aaSAndroid Build Coastguard Worker IDOrPath* const rawIDsOrPaths =
296*c8dee2aaSAndroid Build Coastguard Worker alloc->makeUniqueArray<IDOrPath>(get_glyphIDs(accepted), mapToIDOrPath).release();
297*c8dee2aaSAndroid Build Coastguard Worker
298*c8dee2aaSAndroid Build Coastguard Worker return PathOpSubmitter{isAntiAliased,
299*c8dee2aaSAndroid Build Coastguard Worker strikeToSourceScale,
300*c8dee2aaSAndroid Build Coastguard Worker alloc->makePODSpan(get_positions(accepted)),
301*c8dee2aaSAndroid Build Coastguard Worker SkSpan(rawIDsOrPaths, accepted.size()),
302*c8dee2aaSAndroid Build Coastguard Worker std::move(strikePromise)};
303*c8dee2aaSAndroid Build Coastguard Worker }
304*c8dee2aaSAndroid Build Coastguard Worker
305*c8dee2aaSAndroid Build Coastguard Worker void
submitDraws(SkCanvas * canvas,SkPoint drawOrigin,const SkPaint & paint) const306*c8dee2aaSAndroid Build Coastguard Worker PathOpSubmitter::submitDraws(SkCanvas* canvas, SkPoint drawOrigin, const SkPaint& paint) const {
307*c8dee2aaSAndroid Build Coastguard Worker // Convert the glyph IDs to paths if it hasn't been done yet. This is thread safe.
308*c8dee2aaSAndroid Build Coastguard Worker fConvertIDsToPaths([&]() {
309*c8dee2aaSAndroid Build Coastguard Worker if (SkStrike* strike = fStrikePromise.strike()) {
310*c8dee2aaSAndroid Build Coastguard Worker strike->glyphIDsToPaths(fIDsOrPaths);
311*c8dee2aaSAndroid Build Coastguard Worker
312*c8dee2aaSAndroid Build Coastguard Worker // Drop ref to strike so that it can be purged from the cache if needed.
313*c8dee2aaSAndroid Build Coastguard Worker fStrikePromise.resetStrike();
314*c8dee2aaSAndroid Build Coastguard Worker fPathsAreCreated = true;
315*c8dee2aaSAndroid Build Coastguard Worker }
316*c8dee2aaSAndroid Build Coastguard Worker });
317*c8dee2aaSAndroid Build Coastguard Worker
318*c8dee2aaSAndroid Build Coastguard Worker SkPaint runPaint{paint};
319*c8dee2aaSAndroid Build Coastguard Worker runPaint.setAntiAlias(fIsAntiAliased);
320*c8dee2aaSAndroid Build Coastguard Worker
321*c8dee2aaSAndroid Build Coastguard Worker SkMaskFilterBase* maskFilter = as_MFB(runPaint.getMaskFilter());
322*c8dee2aaSAndroid Build Coastguard Worker
323*c8dee2aaSAndroid Build Coastguard Worker // Calculate the matrix that maps the path glyphs from their size in the strike to
324*c8dee2aaSAndroid Build Coastguard Worker // the graphics source space.
325*c8dee2aaSAndroid Build Coastguard Worker SkMatrix strikeToSource = SkMatrix::Scale(fStrikeToSourceScale, fStrikeToSourceScale);
326*c8dee2aaSAndroid Build Coastguard Worker strikeToSource.postTranslate(drawOrigin.x(), drawOrigin.y());
327*c8dee2aaSAndroid Build Coastguard Worker
328*c8dee2aaSAndroid Build Coastguard Worker // If there are shaders, non-blur mask filters or styles, the path must be scaled into source
329*c8dee2aaSAndroid Build Coastguard Worker // space independently of the CTM. This allows the CTM to be correct for the different effects.
330*c8dee2aaSAndroid Build Coastguard Worker SkStrokeRec style(runPaint);
331*c8dee2aaSAndroid Build Coastguard Worker bool needsExactCTM = runPaint.getShader()
332*c8dee2aaSAndroid Build Coastguard Worker || runPaint.getPathEffect()
333*c8dee2aaSAndroid Build Coastguard Worker || (!style.isFillStyle() && !style.isHairlineStyle())
334*c8dee2aaSAndroid Build Coastguard Worker || (maskFilter != nullptr && !maskFilter->asABlur(nullptr));
335*c8dee2aaSAndroid Build Coastguard Worker if (!needsExactCTM) {
336*c8dee2aaSAndroid Build Coastguard Worker SkMaskFilterBase::BlurRec blurRec;
337*c8dee2aaSAndroid Build Coastguard Worker
338*c8dee2aaSAndroid Build Coastguard Worker // If there is a blur mask filter, then sigma needs to be adjusted to account for the
339*c8dee2aaSAndroid Build Coastguard Worker // scaling of fStrikeToSourceScale.
340*c8dee2aaSAndroid Build Coastguard Worker if (maskFilter != nullptr && maskFilter->asABlur(&blurRec)) {
341*c8dee2aaSAndroid Build Coastguard Worker runPaint.setMaskFilter(
342*c8dee2aaSAndroid Build Coastguard Worker SkMaskFilter::MakeBlur(blurRec.fStyle, blurRec.fSigma / fStrikeToSourceScale));
343*c8dee2aaSAndroid Build Coastguard Worker }
344*c8dee2aaSAndroid Build Coastguard Worker for (auto [idOrPath, pos] : SkMakeZip(fIDsOrPaths, fPositions)) {
345*c8dee2aaSAndroid Build Coastguard Worker // Transform the glyph to source space.
346*c8dee2aaSAndroid Build Coastguard Worker SkMatrix pathMatrix = strikeToSource;
347*c8dee2aaSAndroid Build Coastguard Worker pathMatrix.postTranslate(pos.x(), pos.y());
348*c8dee2aaSAndroid Build Coastguard Worker
349*c8dee2aaSAndroid Build Coastguard Worker SkAutoCanvasRestore acr(canvas, true);
350*c8dee2aaSAndroid Build Coastguard Worker canvas->concat(pathMatrix);
351*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(idOrPath.fPath, runPaint);
352*c8dee2aaSAndroid Build Coastguard Worker }
353*c8dee2aaSAndroid Build Coastguard Worker } else {
354*c8dee2aaSAndroid Build Coastguard Worker // Transform the path to device because the deviceMatrix must be unchanged to
355*c8dee2aaSAndroid Build Coastguard Worker // draw effect, filter or shader paths.
356*c8dee2aaSAndroid Build Coastguard Worker for (auto [idOrPath, pos] : SkMakeZip(fIDsOrPaths, fPositions)) {
357*c8dee2aaSAndroid Build Coastguard Worker // Transform the glyph to source space.
358*c8dee2aaSAndroid Build Coastguard Worker SkMatrix pathMatrix = strikeToSource;
359*c8dee2aaSAndroid Build Coastguard Worker pathMatrix.postTranslate(pos.x(), pos.y());
360*c8dee2aaSAndroid Build Coastguard Worker
361*c8dee2aaSAndroid Build Coastguard Worker SkPath deviceOutline;
362*c8dee2aaSAndroid Build Coastguard Worker idOrPath.fPath.transform(pathMatrix, &deviceOutline);
363*c8dee2aaSAndroid Build Coastguard Worker deviceOutline.setIsVolatile(true);
364*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(deviceOutline, runPaint);
365*c8dee2aaSAndroid Build Coastguard Worker }
366*c8dee2aaSAndroid Build Coastguard Worker }
367*c8dee2aaSAndroid Build Coastguard Worker }
368*c8dee2aaSAndroid Build Coastguard Worker
369*c8dee2aaSAndroid Build Coastguard Worker // -- PathSubRun -----------------------------------------------------------------------------------
370*c8dee2aaSAndroid Build Coastguard Worker class PathSubRun final : public SubRun {
371*c8dee2aaSAndroid Build Coastguard Worker public:
PathSubRun(PathOpSubmitter && pathDrawing)372*c8dee2aaSAndroid Build Coastguard Worker PathSubRun(PathOpSubmitter&& pathDrawing) : fPathDrawing(std::move(pathDrawing)) {}
373*c8dee2aaSAndroid Build Coastguard Worker
Make(SkZip<const SkGlyphID,const SkPoint> accepted,bool isAntiAliased,SkScalar strikeToSourceScale,SkStrikePromise && strikePromise,SubRunAllocator * alloc)374*c8dee2aaSAndroid Build Coastguard Worker static SubRunOwner Make(SkZip<const SkGlyphID, const SkPoint> accepted,
375*c8dee2aaSAndroid Build Coastguard Worker bool isAntiAliased,
376*c8dee2aaSAndroid Build Coastguard Worker SkScalar strikeToSourceScale,
377*c8dee2aaSAndroid Build Coastguard Worker SkStrikePromise&& strikePromise,
378*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc) {
379*c8dee2aaSAndroid Build Coastguard Worker return alloc->makeUnique<PathSubRun>(
380*c8dee2aaSAndroid Build Coastguard Worker PathOpSubmitter::Make(
381*c8dee2aaSAndroid Build Coastguard Worker accepted, isAntiAliased, strikeToSourceScale, std::move(strikePromise), alloc));
382*c8dee2aaSAndroid Build Coastguard Worker }
383*c8dee2aaSAndroid Build Coastguard Worker
draw(SkCanvas * canvas,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt>,const AtlasDrawDelegate &) const384*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas* canvas,
385*c8dee2aaSAndroid Build Coastguard Worker SkPoint drawOrigin,
386*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint,
387*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRefCnt>,
388*c8dee2aaSAndroid Build Coastguard Worker const AtlasDrawDelegate&) const override {
389*c8dee2aaSAndroid Build Coastguard Worker fPathDrawing.submitDraws(canvas, drawOrigin, paint);
390*c8dee2aaSAndroid Build Coastguard Worker }
391*c8dee2aaSAndroid Build Coastguard Worker
392*c8dee2aaSAndroid Build Coastguard Worker int unflattenSize() const override;
393*c8dee2aaSAndroid Build Coastguard Worker
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const394*c8dee2aaSAndroid Build Coastguard Worker bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const override {
395*c8dee2aaSAndroid Build Coastguard Worker return true;
396*c8dee2aaSAndroid Build Coastguard Worker }
testingOnly_atlasSubRun() const397*c8dee2aaSAndroid Build Coastguard Worker const AtlasSubRun* testingOnly_atlasSubRun() const override { return nullptr; }
398*c8dee2aaSAndroid Build Coastguard Worker static SubRunOwner MakeFromBuffer(SkReadBuffer& buffer,
399*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc,
400*c8dee2aaSAndroid Build Coastguard Worker const SkStrikeClient* client);
401*c8dee2aaSAndroid Build Coastguard Worker
402*c8dee2aaSAndroid Build Coastguard Worker protected:
subRunStreamTag() const403*c8dee2aaSAndroid Build Coastguard Worker SubRunStreamTag subRunStreamTag() const override { return SubRunStreamTag::kPathStreamTag; }
404*c8dee2aaSAndroid Build Coastguard Worker void doFlatten(SkWriteBuffer& buffer) const override;
405*c8dee2aaSAndroid Build Coastguard Worker
406*c8dee2aaSAndroid Build Coastguard Worker private:
407*c8dee2aaSAndroid Build Coastguard Worker PathOpSubmitter fPathDrawing;
408*c8dee2aaSAndroid Build Coastguard Worker };
409*c8dee2aaSAndroid Build Coastguard Worker
unflattenSize() const410*c8dee2aaSAndroid Build Coastguard Worker int PathSubRun::unflattenSize() const {
411*c8dee2aaSAndroid Build Coastguard Worker return sizeof(PathSubRun) + fPathDrawing.unflattenSize();
412*c8dee2aaSAndroid Build Coastguard Worker }
413*c8dee2aaSAndroid Build Coastguard Worker
doFlatten(SkWriteBuffer & buffer) const414*c8dee2aaSAndroid Build Coastguard Worker void PathSubRun::doFlatten(SkWriteBuffer& buffer) const {
415*c8dee2aaSAndroid Build Coastguard Worker fPathDrawing.flatten(buffer);
416*c8dee2aaSAndroid Build Coastguard Worker }
417*c8dee2aaSAndroid Build Coastguard Worker
MakeFromBuffer(SkReadBuffer & buffer,SubRunAllocator * alloc,const SkStrikeClient * client)418*c8dee2aaSAndroid Build Coastguard Worker SubRunOwner PathSubRun::MakeFromBuffer(SkReadBuffer& buffer,
419*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc,
420*c8dee2aaSAndroid Build Coastguard Worker const SkStrikeClient* client) {
421*c8dee2aaSAndroid Build Coastguard Worker auto pathOpSubmitter = PathOpSubmitter::MakeFromBuffer(buffer, alloc, client);
422*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(pathOpSubmitter.has_value())) { return nullptr; }
423*c8dee2aaSAndroid Build Coastguard Worker return alloc->makeUnique<PathSubRun>(std::move(*pathOpSubmitter));
424*c8dee2aaSAndroid Build Coastguard Worker }
425*c8dee2aaSAndroid Build Coastguard Worker
426*c8dee2aaSAndroid Build Coastguard Worker // -- DrawableOpSubmitter --------------------------------------------------------------------------
427*c8dee2aaSAndroid Build Coastguard Worker // Shared code for submitting GPU ops for drawing glyphs as drawables.
428*c8dee2aaSAndroid Build Coastguard Worker class DrawableOpSubmitter {
429*c8dee2aaSAndroid Build Coastguard Worker public:
430*c8dee2aaSAndroid Build Coastguard Worker DrawableOpSubmitter() = delete;
431*c8dee2aaSAndroid Build Coastguard Worker DrawableOpSubmitter(const DrawableOpSubmitter&) = delete;
432*c8dee2aaSAndroid Build Coastguard Worker const DrawableOpSubmitter& operator=(const DrawableOpSubmitter&) = delete;
DrawableOpSubmitter(DrawableOpSubmitter && that)433*c8dee2aaSAndroid Build Coastguard Worker DrawableOpSubmitter(DrawableOpSubmitter&& that)
434*c8dee2aaSAndroid Build Coastguard Worker : fStrikeToSourceScale{that.fStrikeToSourceScale}
435*c8dee2aaSAndroid Build Coastguard Worker , fPositions{that.fPositions}
436*c8dee2aaSAndroid Build Coastguard Worker , fIDsOrDrawables{that.fIDsOrDrawables}
437*c8dee2aaSAndroid Build Coastguard Worker , fStrikePromise{std::move(that.fStrikePromise)} {}
operator =(DrawableOpSubmitter && that)438*c8dee2aaSAndroid Build Coastguard Worker DrawableOpSubmitter& operator=(DrawableOpSubmitter&& that) {
439*c8dee2aaSAndroid Build Coastguard Worker this->~DrawableOpSubmitter();
440*c8dee2aaSAndroid Build Coastguard Worker new (this) DrawableOpSubmitter{std::move(that)};
441*c8dee2aaSAndroid Build Coastguard Worker return *this;
442*c8dee2aaSAndroid Build Coastguard Worker }
443*c8dee2aaSAndroid Build Coastguard Worker DrawableOpSubmitter(SkScalar strikeToSourceScale,
444*c8dee2aaSAndroid Build Coastguard Worker SkSpan<SkPoint> positions,
445*c8dee2aaSAndroid Build Coastguard Worker SkSpan<IDOrDrawable> idsOrDrawables,
446*c8dee2aaSAndroid Build Coastguard Worker SkStrikePromise&& strikePromise);
447*c8dee2aaSAndroid Build Coastguard Worker
Make(SkZip<const SkGlyphID,const SkPoint> accepted,SkScalar strikeToSourceScale,SkStrikePromise && strikePromise,SubRunAllocator * alloc)448*c8dee2aaSAndroid Build Coastguard Worker static DrawableOpSubmitter Make(SkZip<const SkGlyphID, const SkPoint> accepted,
449*c8dee2aaSAndroid Build Coastguard Worker SkScalar strikeToSourceScale,
450*c8dee2aaSAndroid Build Coastguard Worker SkStrikePromise&& strikePromise,
451*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc) {
452*c8dee2aaSAndroid Build Coastguard Worker auto mapToIDOrDrawable = [](const SkGlyphID glyphID) { return IDOrDrawable{glyphID}; };
453*c8dee2aaSAndroid Build Coastguard Worker
454*c8dee2aaSAndroid Build Coastguard Worker return DrawableOpSubmitter{
455*c8dee2aaSAndroid Build Coastguard Worker strikeToSourceScale,
456*c8dee2aaSAndroid Build Coastguard Worker alloc->makePODSpan(get_positions(accepted)),
457*c8dee2aaSAndroid Build Coastguard Worker alloc->makePODArray<IDOrDrawable>(get_glyphIDs(accepted), mapToIDOrDrawable),
458*c8dee2aaSAndroid Build Coastguard Worker std::move(strikePromise)};
459*c8dee2aaSAndroid Build Coastguard Worker }
460*c8dee2aaSAndroid Build Coastguard Worker
461*c8dee2aaSAndroid Build Coastguard Worker int unflattenSize() const;
462*c8dee2aaSAndroid Build Coastguard Worker void flatten(SkWriteBuffer& buffer) const;
463*c8dee2aaSAndroid Build Coastguard Worker static std::optional<DrawableOpSubmitter> MakeFromBuffer(SkReadBuffer& buffer,
464*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc,
465*c8dee2aaSAndroid Build Coastguard Worker const SkStrikeClient* client);
466*c8dee2aaSAndroid Build Coastguard Worker void submitDraws(SkCanvas* canvas, SkPoint drawOrigin, const SkPaint& paint) const;
467*c8dee2aaSAndroid Build Coastguard Worker
468*c8dee2aaSAndroid Build Coastguard Worker private:
469*c8dee2aaSAndroid Build Coastguard Worker const SkScalar fStrikeToSourceScale;
470*c8dee2aaSAndroid Build Coastguard Worker const SkSpan<SkPoint> fPositions;
471*c8dee2aaSAndroid Build Coastguard Worker const SkSpan<IDOrDrawable> fIDsOrDrawables;
472*c8dee2aaSAndroid Build Coastguard Worker // When the promise is converted to a strike it acts as the ref on the strike to keep the
473*c8dee2aaSAndroid Build Coastguard Worker // SkDrawable data alive.
474*c8dee2aaSAndroid Build Coastguard Worker mutable SkStrikePromise fStrikePromise;
475*c8dee2aaSAndroid Build Coastguard Worker mutable SkOnce fConvertIDsToDrawables;
476*c8dee2aaSAndroid Build Coastguard Worker };
477*c8dee2aaSAndroid Build Coastguard Worker
unflattenSize() const478*c8dee2aaSAndroid Build Coastguard Worker int DrawableOpSubmitter::unflattenSize() const {
479*c8dee2aaSAndroid Build Coastguard Worker return fPositions.size_bytes() + fIDsOrDrawables.size_bytes();
480*c8dee2aaSAndroid Build Coastguard Worker }
481*c8dee2aaSAndroid Build Coastguard Worker
flatten(SkWriteBuffer & buffer) const482*c8dee2aaSAndroid Build Coastguard Worker void DrawableOpSubmitter::flatten(SkWriteBuffer& buffer) const {
483*c8dee2aaSAndroid Build Coastguard Worker fStrikePromise.flatten(buffer);
484*c8dee2aaSAndroid Build Coastguard Worker
485*c8dee2aaSAndroid Build Coastguard Worker buffer.writeScalar(fStrikeToSourceScale);
486*c8dee2aaSAndroid Build Coastguard Worker buffer.writePointArray(fPositions.data(), SkCount(fPositions));
487*c8dee2aaSAndroid Build Coastguard Worker for (IDOrDrawable idOrDrawable : fIDsOrDrawables) {
488*c8dee2aaSAndroid Build Coastguard Worker buffer.writeInt(idOrDrawable.fGlyphID);
489*c8dee2aaSAndroid Build Coastguard Worker }
490*c8dee2aaSAndroid Build Coastguard Worker }
491*c8dee2aaSAndroid Build Coastguard Worker
MakeFromBuffer(SkReadBuffer & buffer,SubRunAllocator * alloc,const SkStrikeClient * client)492*c8dee2aaSAndroid Build Coastguard Worker std::optional<DrawableOpSubmitter> DrawableOpSubmitter::MakeFromBuffer(
493*c8dee2aaSAndroid Build Coastguard Worker SkReadBuffer& buffer, SubRunAllocator* alloc, const SkStrikeClient* client) {
494*c8dee2aaSAndroid Build Coastguard Worker std::optional<SkStrikePromise> strikePromise =
495*c8dee2aaSAndroid Build Coastguard Worker SkStrikePromise::MakeFromBuffer(buffer, client, SkStrikeCache::GlobalStrikeCache());
496*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(strikePromise.has_value())) {
497*c8dee2aaSAndroid Build Coastguard Worker return std::nullopt;
498*c8dee2aaSAndroid Build Coastguard Worker }
499*c8dee2aaSAndroid Build Coastguard Worker
500*c8dee2aaSAndroid Build Coastguard Worker SkScalar strikeToSourceScale = buffer.readScalar();
501*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(0 < strikeToSourceScale)) { return std::nullopt; }
502*c8dee2aaSAndroid Build Coastguard Worker
503*c8dee2aaSAndroid Build Coastguard Worker SkSpan<SkPoint> positions = MakePointsFromBuffer(buffer, alloc);
504*c8dee2aaSAndroid Build Coastguard Worker if (positions.empty()) { return std::nullopt; }
505*c8dee2aaSAndroid Build Coastguard Worker const int glyphCount = SkCount(positions);
506*c8dee2aaSAndroid Build Coastguard Worker
507*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validateCanReadN<int>(glyphCount)) { return std::nullopt; }
508*c8dee2aaSAndroid Build Coastguard Worker auto idsOrDrawables = alloc->makePODArray<IDOrDrawable>(glyphCount);
509*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < SkToInt(glyphCount); ++i) {
510*c8dee2aaSAndroid Build Coastguard Worker // Remember, we stored an int for glyph id.
511*c8dee2aaSAndroid Build Coastguard Worker idsOrDrawables[i].fGlyphID = SkTo<SkGlyphID>(buffer.readInt());
512*c8dee2aaSAndroid Build Coastguard Worker }
513*c8dee2aaSAndroid Build Coastguard Worker
514*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.isValid()) {
515*c8dee2aaSAndroid Build Coastguard Worker return std::nullopt;
516*c8dee2aaSAndroid Build Coastguard Worker }
517*c8dee2aaSAndroid Build Coastguard Worker
518*c8dee2aaSAndroid Build Coastguard Worker return DrawableOpSubmitter{strikeToSourceScale,
519*c8dee2aaSAndroid Build Coastguard Worker positions,
520*c8dee2aaSAndroid Build Coastguard Worker SkSpan(idsOrDrawables, glyphCount),
521*c8dee2aaSAndroid Build Coastguard Worker std::move(strikePromise.value())};
522*c8dee2aaSAndroid Build Coastguard Worker }
523*c8dee2aaSAndroid Build Coastguard Worker
DrawableOpSubmitter(SkScalar strikeToSourceScale,SkSpan<SkPoint> positions,SkSpan<IDOrDrawable> idsOrDrawables,SkStrikePromise && strikePromise)524*c8dee2aaSAndroid Build Coastguard Worker DrawableOpSubmitter::DrawableOpSubmitter(
525*c8dee2aaSAndroid Build Coastguard Worker SkScalar strikeToSourceScale,
526*c8dee2aaSAndroid Build Coastguard Worker SkSpan<SkPoint> positions,
527*c8dee2aaSAndroid Build Coastguard Worker SkSpan<IDOrDrawable> idsOrDrawables,
528*c8dee2aaSAndroid Build Coastguard Worker SkStrikePromise&& strikePromise)
529*c8dee2aaSAndroid Build Coastguard Worker : fStrikeToSourceScale{strikeToSourceScale}
530*c8dee2aaSAndroid Build Coastguard Worker , fPositions{positions}
531*c8dee2aaSAndroid Build Coastguard Worker , fIDsOrDrawables{idsOrDrawables}
532*c8dee2aaSAndroid Build Coastguard Worker , fStrikePromise(std::move(strikePromise)) {
533*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fPositions.empty());
534*c8dee2aaSAndroid Build Coastguard Worker }
535*c8dee2aaSAndroid Build Coastguard Worker
536*c8dee2aaSAndroid Build Coastguard Worker void
submitDraws(SkCanvas * canvas,SkPoint drawOrigin,const SkPaint & paint) const537*c8dee2aaSAndroid Build Coastguard Worker DrawableOpSubmitter::submitDraws(SkCanvas* canvas, SkPoint drawOrigin,const SkPaint& paint) const {
538*c8dee2aaSAndroid Build Coastguard Worker // Convert glyph IDs to Drawables if it hasn't been done yet.
539*c8dee2aaSAndroid Build Coastguard Worker fConvertIDsToDrawables([&]() {
540*c8dee2aaSAndroid Build Coastguard Worker fStrikePromise.strike()->glyphIDsToDrawables(fIDsOrDrawables);
541*c8dee2aaSAndroid Build Coastguard Worker // Do not call resetStrike() because the strike must remain owned to ensure the Drawable
542*c8dee2aaSAndroid Build Coastguard Worker // data is not freed.
543*c8dee2aaSAndroid Build Coastguard Worker });
544*c8dee2aaSAndroid Build Coastguard Worker
545*c8dee2aaSAndroid Build Coastguard Worker // Calculate the matrix that maps the path glyphs from their size in the strike to
546*c8dee2aaSAndroid Build Coastguard Worker // the graphics source space.
547*c8dee2aaSAndroid Build Coastguard Worker SkMatrix strikeToSource = SkMatrix::Scale(fStrikeToSourceScale, fStrikeToSourceScale);
548*c8dee2aaSAndroid Build Coastguard Worker strikeToSource.postTranslate(drawOrigin.x(), drawOrigin.y());
549*c8dee2aaSAndroid Build Coastguard Worker
550*c8dee2aaSAndroid Build Coastguard Worker // Transform the path to device because the deviceMatrix must be unchanged to
551*c8dee2aaSAndroid Build Coastguard Worker // draw effect, filter or shader paths.
552*c8dee2aaSAndroid Build Coastguard Worker for (auto [i, position] : SkMakeEnumerate(fPositions)) {
553*c8dee2aaSAndroid Build Coastguard Worker SkDrawable* drawable = fIDsOrDrawables[i].fDrawable;
554*c8dee2aaSAndroid Build Coastguard Worker
555*c8dee2aaSAndroid Build Coastguard Worker if (drawable == nullptr) {
556*c8dee2aaSAndroid Build Coastguard Worker // This better be pinned to keep the drawable data alive.
557*c8dee2aaSAndroid Build Coastguard Worker fStrikePromise.strike()->verifyPinnedStrike();
558*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("Drawable should not be nullptr.");
559*c8dee2aaSAndroid Build Coastguard Worker continue;
560*c8dee2aaSAndroid Build Coastguard Worker }
561*c8dee2aaSAndroid Build Coastguard Worker
562*c8dee2aaSAndroid Build Coastguard Worker // Transform the glyph to source space.
563*c8dee2aaSAndroid Build Coastguard Worker SkMatrix pathMatrix = strikeToSource;
564*c8dee2aaSAndroid Build Coastguard Worker pathMatrix.postTranslate(position.x(), position.y());
565*c8dee2aaSAndroid Build Coastguard Worker
566*c8dee2aaSAndroid Build Coastguard Worker SkAutoCanvasRestore acr(canvas, false);
567*c8dee2aaSAndroid Build Coastguard Worker SkRect drawableBounds = drawable->getBounds();
568*c8dee2aaSAndroid Build Coastguard Worker pathMatrix.mapRect(&drawableBounds);
569*c8dee2aaSAndroid Build Coastguard Worker canvas->saveLayer(&drawableBounds, &paint);
570*c8dee2aaSAndroid Build Coastguard Worker drawable->draw(canvas, &pathMatrix);
571*c8dee2aaSAndroid Build Coastguard Worker }
572*c8dee2aaSAndroid Build Coastguard Worker }
573*c8dee2aaSAndroid Build Coastguard Worker
574*c8dee2aaSAndroid Build Coastguard Worker // -- DrawableSubRun -------------------------------------------------------------------------------
575*c8dee2aaSAndroid Build Coastguard Worker class DrawableSubRun : public SubRun {
576*c8dee2aaSAndroid Build Coastguard Worker public:
DrawableSubRun(DrawableOpSubmitter && drawingDrawing)577*c8dee2aaSAndroid Build Coastguard Worker DrawableSubRun(DrawableOpSubmitter&& drawingDrawing)
578*c8dee2aaSAndroid Build Coastguard Worker : fDrawingDrawing(std::move(drawingDrawing)) {}
579*c8dee2aaSAndroid Build Coastguard Worker
Make(SkZip<const SkGlyphID,const SkPoint> drawables,SkScalar strikeToSourceScale,SkStrikePromise && strikePromise,SubRunAllocator * alloc)580*c8dee2aaSAndroid Build Coastguard Worker static SubRunOwner Make(SkZip<const SkGlyphID, const SkPoint> drawables,
581*c8dee2aaSAndroid Build Coastguard Worker SkScalar strikeToSourceScale,
582*c8dee2aaSAndroid Build Coastguard Worker SkStrikePromise&& strikePromise,
583*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc) {
584*c8dee2aaSAndroid Build Coastguard Worker return alloc->makeUnique<DrawableSubRun>(
585*c8dee2aaSAndroid Build Coastguard Worker DrawableOpSubmitter::Make(drawables,
586*c8dee2aaSAndroid Build Coastguard Worker strikeToSourceScale,
587*c8dee2aaSAndroid Build Coastguard Worker std::move(strikePromise),
588*c8dee2aaSAndroid Build Coastguard Worker alloc));
589*c8dee2aaSAndroid Build Coastguard Worker }
590*c8dee2aaSAndroid Build Coastguard Worker
591*c8dee2aaSAndroid Build Coastguard Worker static SubRunOwner MakeFromBuffer(SkReadBuffer& buffer,
592*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc,
593*c8dee2aaSAndroid Build Coastguard Worker const SkStrikeClient* client);
594*c8dee2aaSAndroid Build Coastguard Worker
draw(SkCanvas * canvas,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt>,const AtlasDrawDelegate &) const595*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas* canvas,
596*c8dee2aaSAndroid Build Coastguard Worker SkPoint drawOrigin,
597*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint,
598*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRefCnt>,
599*c8dee2aaSAndroid Build Coastguard Worker const AtlasDrawDelegate&) const override {
600*c8dee2aaSAndroid Build Coastguard Worker fDrawingDrawing.submitDraws(canvas, drawOrigin, paint);
601*c8dee2aaSAndroid Build Coastguard Worker }
602*c8dee2aaSAndroid Build Coastguard Worker
603*c8dee2aaSAndroid Build Coastguard Worker int unflattenSize() const override;
604*c8dee2aaSAndroid Build Coastguard Worker
605*c8dee2aaSAndroid Build Coastguard Worker bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const override;
606*c8dee2aaSAndroid Build Coastguard Worker
607*c8dee2aaSAndroid Build Coastguard Worker const AtlasSubRun* testingOnly_atlasSubRun() const override;
608*c8dee2aaSAndroid Build Coastguard Worker
609*c8dee2aaSAndroid Build Coastguard Worker protected:
subRunStreamTag() const610*c8dee2aaSAndroid Build Coastguard Worker SubRunStreamTag subRunStreamTag() const override { return SubRunStreamTag::kDrawableStreamTag; }
611*c8dee2aaSAndroid Build Coastguard Worker void doFlatten(SkWriteBuffer& buffer) const override;
612*c8dee2aaSAndroid Build Coastguard Worker
613*c8dee2aaSAndroid Build Coastguard Worker private:
614*c8dee2aaSAndroid Build Coastguard Worker DrawableOpSubmitter fDrawingDrawing;
615*c8dee2aaSAndroid Build Coastguard Worker };
616*c8dee2aaSAndroid Build Coastguard Worker
unflattenSize() const617*c8dee2aaSAndroid Build Coastguard Worker int DrawableSubRun::unflattenSize() const {
618*c8dee2aaSAndroid Build Coastguard Worker return sizeof(DrawableSubRun) + fDrawingDrawing.unflattenSize();
619*c8dee2aaSAndroid Build Coastguard Worker }
620*c8dee2aaSAndroid Build Coastguard Worker
doFlatten(SkWriteBuffer & buffer) const621*c8dee2aaSAndroid Build Coastguard Worker void DrawableSubRun::doFlatten(SkWriteBuffer& buffer) const {
622*c8dee2aaSAndroid Build Coastguard Worker fDrawingDrawing.flatten(buffer);
623*c8dee2aaSAndroid Build Coastguard Worker }
624*c8dee2aaSAndroid Build Coastguard Worker
MakeFromBuffer(SkReadBuffer & buffer,SubRunAllocator * alloc,const SkStrikeClient * client)625*c8dee2aaSAndroid Build Coastguard Worker SubRunOwner DrawableSubRun::MakeFromBuffer(SkReadBuffer& buffer,
626*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc,
627*c8dee2aaSAndroid Build Coastguard Worker const SkStrikeClient* client) {
628*c8dee2aaSAndroid Build Coastguard Worker auto drawableOpSubmitter = DrawableOpSubmitter::MakeFromBuffer(buffer, alloc, client);
629*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(drawableOpSubmitter.has_value())) { return nullptr; }
630*c8dee2aaSAndroid Build Coastguard Worker return alloc->makeUnique<DrawableSubRun>(std::move(*drawableOpSubmitter));
631*c8dee2aaSAndroid Build Coastguard Worker }
632*c8dee2aaSAndroid Build Coastguard Worker
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const633*c8dee2aaSAndroid Build Coastguard Worker bool DrawableSubRun::canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const {
634*c8dee2aaSAndroid Build Coastguard Worker return true;
635*c8dee2aaSAndroid Build Coastguard Worker }
636*c8dee2aaSAndroid Build Coastguard Worker
testingOnly_atlasSubRun() const637*c8dee2aaSAndroid Build Coastguard Worker const AtlasSubRun* DrawableSubRun::testingOnly_atlasSubRun() const {
638*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
639*c8dee2aaSAndroid Build Coastguard Worker }
640*c8dee2aaSAndroid Build Coastguard Worker
641*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
642*c8dee2aaSAndroid Build Coastguard Worker enum ClipMethod {
643*c8dee2aaSAndroid Build Coastguard Worker kClippedOut,
644*c8dee2aaSAndroid Build Coastguard Worker kUnclipped,
645*c8dee2aaSAndroid Build Coastguard Worker kGPUClipped,
646*c8dee2aaSAndroid Build Coastguard Worker kGeometryClipped
647*c8dee2aaSAndroid Build Coastguard Worker };
648*c8dee2aaSAndroid Build Coastguard Worker
649*c8dee2aaSAndroid Build Coastguard Worker std::tuple<ClipMethod, SkIRect>
calculate_clip(const GrClip * clip,SkRect deviceBounds,SkRect glyphBounds)650*c8dee2aaSAndroid Build Coastguard Worker calculate_clip(const GrClip* clip, SkRect deviceBounds, SkRect glyphBounds) {
651*c8dee2aaSAndroid Build Coastguard Worker if (clip == nullptr && !deviceBounds.intersects(glyphBounds)) {
652*c8dee2aaSAndroid Build Coastguard Worker return {kClippedOut, SkIRect::MakeEmpty()};
653*c8dee2aaSAndroid Build Coastguard Worker } else if (clip != nullptr) {
654*c8dee2aaSAndroid Build Coastguard Worker switch (auto result = clip->preApply(glyphBounds, GrAA::kNo); result.fEffect) {
655*c8dee2aaSAndroid Build Coastguard Worker case GrClip::Effect::kClippedOut:
656*c8dee2aaSAndroid Build Coastguard Worker return {kClippedOut, SkIRect::MakeEmpty()};
657*c8dee2aaSAndroid Build Coastguard Worker case GrClip::Effect::kUnclipped:
658*c8dee2aaSAndroid Build Coastguard Worker return {kUnclipped, SkIRect::MakeEmpty()};
659*c8dee2aaSAndroid Build Coastguard Worker case GrClip::Effect::kClipped: {
660*c8dee2aaSAndroid Build Coastguard Worker if (result.fIsRRect && result.fRRect.isRect()) {
661*c8dee2aaSAndroid Build Coastguard Worker SkRect r = result.fRRect.rect();
662*c8dee2aaSAndroid Build Coastguard Worker if (result.fAA == GrAA::kNo || GrClip::IsPixelAligned(r)) {
663*c8dee2aaSAndroid Build Coastguard Worker SkIRect clipRect = SkIRect::MakeEmpty();
664*c8dee2aaSAndroid Build Coastguard Worker // Clip geometrically during onPrepare using clipRect.
665*c8dee2aaSAndroid Build Coastguard Worker r.round(&clipRect);
666*c8dee2aaSAndroid Build Coastguard Worker if (clipRect.contains(glyphBounds)) {
667*c8dee2aaSAndroid Build Coastguard Worker // If fully within the clip, signal no clipping using the empty rect.
668*c8dee2aaSAndroid Build Coastguard Worker return {kUnclipped, SkIRect::MakeEmpty()};
669*c8dee2aaSAndroid Build Coastguard Worker }
670*c8dee2aaSAndroid Build Coastguard Worker // Use the clipRect to clip the geometry.
671*c8dee2aaSAndroid Build Coastguard Worker return {kGeometryClipped, clipRect};
672*c8dee2aaSAndroid Build Coastguard Worker }
673*c8dee2aaSAndroid Build Coastguard Worker // Partial pixel clipped at this point. Have the GPU handle it.
674*c8dee2aaSAndroid Build Coastguard Worker }
675*c8dee2aaSAndroid Build Coastguard Worker }
676*c8dee2aaSAndroid Build Coastguard Worker break;
677*c8dee2aaSAndroid Build Coastguard Worker }
678*c8dee2aaSAndroid Build Coastguard Worker }
679*c8dee2aaSAndroid Build Coastguard Worker return {kGPUClipped, SkIRect::MakeEmpty()};
680*c8dee2aaSAndroid Build Coastguard Worker }
681*c8dee2aaSAndroid Build Coastguard Worker #endif // defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
682*c8dee2aaSAndroid Build Coastguard Worker
683*c8dee2aaSAndroid Build Coastguard Worker // -- DirectMaskSubRun -----------------------------------------------------------------------------
684*c8dee2aaSAndroid Build Coastguard Worker class DirectMaskSubRun final : public SubRun, public AtlasSubRun {
685*c8dee2aaSAndroid Build Coastguard Worker public:
DirectMaskSubRun(VertexFiller && vertexFiller,GlyphVector && glyphs)686*c8dee2aaSAndroid Build Coastguard Worker DirectMaskSubRun(VertexFiller&& vertexFiller,
687*c8dee2aaSAndroid Build Coastguard Worker GlyphVector&& glyphs)
688*c8dee2aaSAndroid Build Coastguard Worker : fVertexFiller{std::move(vertexFiller)}
689*c8dee2aaSAndroid Build Coastguard Worker , fGlyphs{std::move(glyphs)} {}
690*c8dee2aaSAndroid Build Coastguard Worker
Make(SkRect creationBounds,SkZip<const SkPackedGlyphID,const SkPoint> accepted,const SkMatrix & creationMatrix,SkStrikePromise && strikePromise,MaskFormat maskType,SubRunAllocator * alloc)691*c8dee2aaSAndroid Build Coastguard Worker static SubRunOwner Make(SkRect creationBounds,
692*c8dee2aaSAndroid Build Coastguard Worker SkZip<const SkPackedGlyphID, const SkPoint> accepted,
693*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& creationMatrix,
694*c8dee2aaSAndroid Build Coastguard Worker SkStrikePromise&& strikePromise,
695*c8dee2aaSAndroid Build Coastguard Worker MaskFormat maskType,
696*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc) {
697*c8dee2aaSAndroid Build Coastguard Worker auto vertexFiller = VertexFiller::Make(maskType,
698*c8dee2aaSAndroid Build Coastguard Worker creationMatrix,
699*c8dee2aaSAndroid Build Coastguard Worker creationBounds,
700*c8dee2aaSAndroid Build Coastguard Worker get_positions(accepted),
701*c8dee2aaSAndroid Build Coastguard Worker alloc,
702*c8dee2aaSAndroid Build Coastguard Worker kIsDirect);
703*c8dee2aaSAndroid Build Coastguard Worker
704*c8dee2aaSAndroid Build Coastguard Worker auto glyphVector =
705*c8dee2aaSAndroid Build Coastguard Worker GlyphVector::Make(std::move(strikePromise), get_packedIDs(accepted), alloc);
706*c8dee2aaSAndroid Build Coastguard Worker
707*c8dee2aaSAndroid Build Coastguard Worker return alloc->makeUnique<DirectMaskSubRun>(std::move(vertexFiller), std::move(glyphVector));
708*c8dee2aaSAndroid Build Coastguard Worker }
709*c8dee2aaSAndroid Build Coastguard Worker
MakeFromBuffer(SkReadBuffer & buffer,SubRunAllocator * alloc,const SkStrikeClient * client)710*c8dee2aaSAndroid Build Coastguard Worker static SubRunOwner MakeFromBuffer(SkReadBuffer& buffer,
711*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc,
712*c8dee2aaSAndroid Build Coastguard Worker const SkStrikeClient* client) {
713*c8dee2aaSAndroid Build Coastguard Worker auto vertexFiller = VertexFiller::MakeFromBuffer(buffer, alloc);
714*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(vertexFiller.has_value())) { return nullptr; }
715*c8dee2aaSAndroid Build Coastguard Worker
716*c8dee2aaSAndroid Build Coastguard Worker auto glyphVector = GlyphVector::MakeFromBuffer(buffer, client, alloc);
717*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(glyphVector.has_value())) { return nullptr; }
718*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(SkCount(glyphVector->glyphs()) == vertexFiller->count())) {
719*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
720*c8dee2aaSAndroid Build Coastguard Worker }
721*c8dee2aaSAndroid Build Coastguard Worker
722*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(buffer.isValid());
723*c8dee2aaSAndroid Build Coastguard Worker return alloc->makeUnique<DirectMaskSubRun>(
724*c8dee2aaSAndroid Build Coastguard Worker std::move(*vertexFiller), std::move(*glyphVector));
725*c8dee2aaSAndroid Build Coastguard Worker }
726*c8dee2aaSAndroid Build Coastguard Worker
draw(SkCanvas *,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> subRunStorage,const AtlasDrawDelegate & drawAtlas) const727*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas*,
728*c8dee2aaSAndroid Build Coastguard Worker SkPoint drawOrigin,
729*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint,
730*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRefCnt> subRunStorage,
731*c8dee2aaSAndroid Build Coastguard Worker const AtlasDrawDelegate& drawAtlas) const override {
732*c8dee2aaSAndroid Build Coastguard Worker drawAtlas(this, drawOrigin, paint, std::move(subRunStorage),
733*c8dee2aaSAndroid Build Coastguard Worker {/* isSDF = */false, fVertexFiller.isLCD(), fVertexFiller.grMaskType()});
734*c8dee2aaSAndroid Build Coastguard Worker }
735*c8dee2aaSAndroid Build Coastguard Worker
unflattenSize() const736*c8dee2aaSAndroid Build Coastguard Worker int unflattenSize() const override {
737*c8dee2aaSAndroid Build Coastguard Worker return sizeof(DirectMaskSubRun) +
738*c8dee2aaSAndroid Build Coastguard Worker fGlyphs.unflattenSize() +
739*c8dee2aaSAndroid Build Coastguard Worker fVertexFiller.unflattenSize();
740*c8dee2aaSAndroid Build Coastguard Worker }
741*c8dee2aaSAndroid Build Coastguard Worker
glyphCount() const742*c8dee2aaSAndroid Build Coastguard Worker int glyphCount() const override {
743*c8dee2aaSAndroid Build Coastguard Worker return SkCount(fGlyphs.glyphs());
744*c8dee2aaSAndroid Build Coastguard Worker }
745*c8dee2aaSAndroid Build Coastguard Worker
glyphs() const746*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const Glyph*> glyphs() const override {
747*c8dee2aaSAndroid Build Coastguard Worker return fGlyphs.glyphs();
748*c8dee2aaSAndroid Build Coastguard Worker }
749*c8dee2aaSAndroid Build Coastguard Worker
maskFormat() const750*c8dee2aaSAndroid Build Coastguard Worker MaskFormat maskFormat() const override { return fVertexFiller.grMaskType(); }
751*c8dee2aaSAndroid Build Coastguard Worker
glyphSrcPadding() const752*c8dee2aaSAndroid Build Coastguard Worker int glyphSrcPadding() const override { return 0; }
753*c8dee2aaSAndroid Build Coastguard Worker
instanceFlags() const754*c8dee2aaSAndroid Build Coastguard Worker unsigned short instanceFlags() const override {
755*c8dee2aaSAndroid Build Coastguard Worker return (unsigned short)fVertexFiller.grMaskType();
756*c8dee2aaSAndroid Build Coastguard Worker }
757*c8dee2aaSAndroid Build Coastguard Worker
testingOnly_packedGlyphIDToGlyph(StrikeCache * cache) const758*c8dee2aaSAndroid Build Coastguard Worker void testingOnly_packedGlyphIDToGlyph(StrikeCache* cache) const override {
759*c8dee2aaSAndroid Build Coastguard Worker fGlyphs.packedGlyphIDToGlyph(cache);
760*c8dee2aaSAndroid Build Coastguard Worker }
761*c8dee2aaSAndroid Build Coastguard Worker
762*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
vertexStride(const SkMatrix & drawMatrix) const763*c8dee2aaSAndroid Build Coastguard Worker size_t vertexStride(const SkMatrix& drawMatrix) const override {
764*c8dee2aaSAndroid Build Coastguard Worker return fVertexFiller.vertexStride(drawMatrix);
765*c8dee2aaSAndroid Build Coastguard Worker }
766*c8dee2aaSAndroid Build Coastguard Worker
makeAtlasTextOp(const GrClip * clip,const SkMatrix & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> && subRunStorage,skgpu::ganesh::SurfaceDrawContext * sdc) const767*c8dee2aaSAndroid Build Coastguard Worker std::tuple<const GrClip*, GrOp::Owner> makeAtlasTextOp(
768*c8dee2aaSAndroid Build Coastguard Worker const GrClip* clip,
769*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& viewMatrix,
770*c8dee2aaSAndroid Build Coastguard Worker SkPoint drawOrigin,
771*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint,
772*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRefCnt>&& subRunStorage,
773*c8dee2aaSAndroid Build Coastguard Worker skgpu::ganesh::SurfaceDrawContext* sdc) const override {
774*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->glyphCount() != 0);
775*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& positionMatrix = position_matrix(viewMatrix, drawOrigin);
776*c8dee2aaSAndroid Build Coastguard Worker
777*c8dee2aaSAndroid Build Coastguard Worker auto [integerTranslate, subRunDeviceBounds] =
778*c8dee2aaSAndroid Build Coastguard Worker fVertexFiller.deviceRectAndCheckTransform(positionMatrix);
779*c8dee2aaSAndroid Build Coastguard Worker if (subRunDeviceBounds.isEmpty()) {
780*c8dee2aaSAndroid Build Coastguard Worker return {nullptr, nullptr};
781*c8dee2aaSAndroid Build Coastguard Worker }
782*c8dee2aaSAndroid Build Coastguard Worker // Rect for optimized bounds clipping when doing an integer translate.
783*c8dee2aaSAndroid Build Coastguard Worker SkIRect geometricClipRect = SkIRect::MakeEmpty();
784*c8dee2aaSAndroid Build Coastguard Worker if (integerTranslate) {
785*c8dee2aaSAndroid Build Coastguard Worker // We can clip geometrically using clipRect and ignore clip when an axis-aligned
786*c8dee2aaSAndroid Build Coastguard Worker // rectangular non-AA clip is used. If clipRect is empty, and clip is nullptr, then
787*c8dee2aaSAndroid Build Coastguard Worker // there is no clipping needed.
788*c8dee2aaSAndroid Build Coastguard Worker const SkRect deviceBounds = SkRect::MakeWH(sdc->width(), sdc->height());
789*c8dee2aaSAndroid Build Coastguard Worker auto [clipMethod, clipRect] = calculate_clip(clip, deviceBounds, subRunDeviceBounds);
790*c8dee2aaSAndroid Build Coastguard Worker
791*c8dee2aaSAndroid Build Coastguard Worker switch (clipMethod) {
792*c8dee2aaSAndroid Build Coastguard Worker case kClippedOut:
793*c8dee2aaSAndroid Build Coastguard Worker // Returning nullptr as op means skip this op.
794*c8dee2aaSAndroid Build Coastguard Worker return {nullptr, nullptr};
795*c8dee2aaSAndroid Build Coastguard Worker case kUnclipped:
796*c8dee2aaSAndroid Build Coastguard Worker case kGeometryClipped:
797*c8dee2aaSAndroid Build Coastguard Worker // GPU clip is not needed.
798*c8dee2aaSAndroid Build Coastguard Worker clip = nullptr;
799*c8dee2aaSAndroid Build Coastguard Worker break;
800*c8dee2aaSAndroid Build Coastguard Worker case kGPUClipped:
801*c8dee2aaSAndroid Build Coastguard Worker // Use th GPU clip; clipRect is ignored.
802*c8dee2aaSAndroid Build Coastguard Worker break;
803*c8dee2aaSAndroid Build Coastguard Worker }
804*c8dee2aaSAndroid Build Coastguard Worker geometricClipRect = clipRect;
805*c8dee2aaSAndroid Build Coastguard Worker
806*c8dee2aaSAndroid Build Coastguard Worker if (!geometricClipRect.isEmpty()) { SkASSERT(clip == nullptr); }
807*c8dee2aaSAndroid Build Coastguard Worker }
808*c8dee2aaSAndroid Build Coastguard Worker
809*c8dee2aaSAndroid Build Coastguard Worker GrPaint grPaint;
810*c8dee2aaSAndroid Build Coastguard Worker const SkPMColor4f drawingColor = calculate_colors(sdc,
811*c8dee2aaSAndroid Build Coastguard Worker paint,
812*c8dee2aaSAndroid Build Coastguard Worker viewMatrix,
813*c8dee2aaSAndroid Build Coastguard Worker fVertexFiller.grMaskType(),
814*c8dee2aaSAndroid Build Coastguard Worker &grPaint);
815*c8dee2aaSAndroid Build Coastguard Worker
816*c8dee2aaSAndroid Build Coastguard Worker auto geometry = AtlasTextOp::Geometry::Make(*this,
817*c8dee2aaSAndroid Build Coastguard Worker viewMatrix,
818*c8dee2aaSAndroid Build Coastguard Worker drawOrigin,
819*c8dee2aaSAndroid Build Coastguard Worker geometricClipRect,
820*c8dee2aaSAndroid Build Coastguard Worker std::move(subRunStorage),
821*c8dee2aaSAndroid Build Coastguard Worker drawingColor,
822*c8dee2aaSAndroid Build Coastguard Worker sdc->arenaAlloc());
823*c8dee2aaSAndroid Build Coastguard Worker
824*c8dee2aaSAndroid Build Coastguard Worker GrRecordingContext* const rContext = sdc->recordingContext();
825*c8dee2aaSAndroid Build Coastguard Worker
826*c8dee2aaSAndroid Build Coastguard Worker GrOp::Owner op = GrOp::Make<AtlasTextOp>(rContext,
827*c8dee2aaSAndroid Build Coastguard Worker fVertexFiller.opMaskType(),
828*c8dee2aaSAndroid Build Coastguard Worker !integerTranslate,
829*c8dee2aaSAndroid Build Coastguard Worker this->glyphCount(),
830*c8dee2aaSAndroid Build Coastguard Worker subRunDeviceBounds,
831*c8dee2aaSAndroid Build Coastguard Worker geometry,
832*c8dee2aaSAndroid Build Coastguard Worker sdc->colorInfo(),
833*c8dee2aaSAndroid Build Coastguard Worker std::move(grPaint));
834*c8dee2aaSAndroid Build Coastguard Worker return {clip, std::move(op)};
835*c8dee2aaSAndroid Build Coastguard Worker }
836*c8dee2aaSAndroid Build Coastguard Worker
fillVertexData(void * vertexDst,int offset,int count,GrColor color,const SkMatrix & drawMatrix,SkPoint drawOrigin,SkIRect clip) const837*c8dee2aaSAndroid Build Coastguard Worker void fillVertexData(void* vertexDst, int offset, int count,
838*c8dee2aaSAndroid Build Coastguard Worker GrColor color,
839*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& drawMatrix, SkPoint drawOrigin,
840*c8dee2aaSAndroid Build Coastguard Worker SkIRect clip) const override {
841*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix positionMatrix = position_matrix(drawMatrix, drawOrigin);
842*c8dee2aaSAndroid Build Coastguard Worker fVertexFiller.fillVertexData(offset, count,
843*c8dee2aaSAndroid Build Coastguard Worker fGlyphs.glyphs(),
844*c8dee2aaSAndroid Build Coastguard Worker color,
845*c8dee2aaSAndroid Build Coastguard Worker positionMatrix,
846*c8dee2aaSAndroid Build Coastguard Worker clip,
847*c8dee2aaSAndroid Build Coastguard Worker vertexDst);
848*c8dee2aaSAndroid Build Coastguard Worker }
849*c8dee2aaSAndroid Build Coastguard Worker #endif // defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
850*c8dee2aaSAndroid Build Coastguard Worker
regenerateAtlas(int begin,int end,RegenerateAtlasDelegate regenerateAtlas) const851*c8dee2aaSAndroid Build Coastguard Worker std::tuple<bool, int> regenerateAtlas(int begin, int end,
852*c8dee2aaSAndroid Build Coastguard Worker RegenerateAtlasDelegate regenerateAtlas) const override {
853*c8dee2aaSAndroid Build Coastguard Worker return regenerateAtlas(
854*c8dee2aaSAndroid Build Coastguard Worker &fGlyphs, begin, end, fVertexFiller.grMaskType(), this->glyphSrcPadding());
855*c8dee2aaSAndroid Build Coastguard Worker }
856*c8dee2aaSAndroid Build Coastguard Worker
vertexFiller() const857*c8dee2aaSAndroid Build Coastguard Worker const VertexFiller& vertexFiller() const override { return fVertexFiller; }
858*c8dee2aaSAndroid Build Coastguard Worker
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const859*c8dee2aaSAndroid Build Coastguard Worker bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const override {
860*c8dee2aaSAndroid Build Coastguard Worker auto [reuse, _] = fVertexFiller.deviceRectAndCheckTransform(positionMatrix);
861*c8dee2aaSAndroid Build Coastguard Worker return reuse;
862*c8dee2aaSAndroid Build Coastguard Worker }
863*c8dee2aaSAndroid Build Coastguard Worker
testingOnly_atlasSubRun() const864*c8dee2aaSAndroid Build Coastguard Worker const AtlasSubRun* testingOnly_atlasSubRun() const override {
865*c8dee2aaSAndroid Build Coastguard Worker return this;
866*c8dee2aaSAndroid Build Coastguard Worker }
867*c8dee2aaSAndroid Build Coastguard Worker
868*c8dee2aaSAndroid Build Coastguard Worker protected:
subRunStreamTag() const869*c8dee2aaSAndroid Build Coastguard Worker SubRunStreamTag subRunStreamTag() const override {
870*c8dee2aaSAndroid Build Coastguard Worker return SubRunStreamTag::kDirectMaskStreamTag;
871*c8dee2aaSAndroid Build Coastguard Worker }
872*c8dee2aaSAndroid Build Coastguard Worker
doFlatten(SkWriteBuffer & buffer) const873*c8dee2aaSAndroid Build Coastguard Worker void doFlatten(SkWriteBuffer& buffer) const override {
874*c8dee2aaSAndroid Build Coastguard Worker fVertexFiller.flatten(buffer);
875*c8dee2aaSAndroid Build Coastguard Worker fGlyphs.flatten(buffer);
876*c8dee2aaSAndroid Build Coastguard Worker }
877*c8dee2aaSAndroid Build Coastguard Worker
878*c8dee2aaSAndroid Build Coastguard Worker private:
879*c8dee2aaSAndroid Build Coastguard Worker const VertexFiller fVertexFiller;
880*c8dee2aaSAndroid Build Coastguard Worker
881*c8dee2aaSAndroid Build Coastguard Worker // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
882*c8dee2aaSAndroid Build Coastguard Worker // be single threaded.
883*c8dee2aaSAndroid Build Coastguard Worker mutable GlyphVector fGlyphs;
884*c8dee2aaSAndroid Build Coastguard Worker };
885*c8dee2aaSAndroid Build Coastguard Worker
886*c8dee2aaSAndroid Build Coastguard Worker // -- TransformedMaskSubRun ------------------------------------------------------------------------
887*c8dee2aaSAndroid Build Coastguard Worker class TransformedMaskSubRun final : public SubRun, public AtlasSubRun {
888*c8dee2aaSAndroid Build Coastguard Worker public:
TransformedMaskSubRun(bool isBigEnough,VertexFiller && vertexFiller,GlyphVector && glyphs)889*c8dee2aaSAndroid Build Coastguard Worker TransformedMaskSubRun(bool isBigEnough,
890*c8dee2aaSAndroid Build Coastguard Worker VertexFiller&& vertexFiller,
891*c8dee2aaSAndroid Build Coastguard Worker GlyphVector&& glyphs)
892*c8dee2aaSAndroid Build Coastguard Worker : fIsBigEnough{isBigEnough}
893*c8dee2aaSAndroid Build Coastguard Worker , fVertexFiller{std::move(vertexFiller)}
894*c8dee2aaSAndroid Build Coastguard Worker , fGlyphs{std::move(glyphs)} {}
895*c8dee2aaSAndroid Build Coastguard Worker
Make(SkZip<const SkPackedGlyphID,const SkPoint> accepted,const SkMatrix & initialPositionMatrix,SkStrikePromise && strikePromise,SkMatrix creationMatrix,SkRect creationBounds,MaskFormat maskType,SubRunAllocator * alloc)896*c8dee2aaSAndroid Build Coastguard Worker static SubRunOwner Make(SkZip<const SkPackedGlyphID, const SkPoint> accepted,
897*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& initialPositionMatrix,
898*c8dee2aaSAndroid Build Coastguard Worker SkStrikePromise&& strikePromise,
899*c8dee2aaSAndroid Build Coastguard Worker SkMatrix creationMatrix,
900*c8dee2aaSAndroid Build Coastguard Worker SkRect creationBounds,
901*c8dee2aaSAndroid Build Coastguard Worker MaskFormat maskType,
902*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc) {
903*c8dee2aaSAndroid Build Coastguard Worker auto vertexFiller = VertexFiller::Make(maskType,
904*c8dee2aaSAndroid Build Coastguard Worker creationMatrix,
905*c8dee2aaSAndroid Build Coastguard Worker creationBounds,
906*c8dee2aaSAndroid Build Coastguard Worker get_positions(accepted),
907*c8dee2aaSAndroid Build Coastguard Worker alloc,
908*c8dee2aaSAndroid Build Coastguard Worker kIsTransformed);
909*c8dee2aaSAndroid Build Coastguard Worker
910*c8dee2aaSAndroid Build Coastguard Worker auto glyphVector = GlyphVector::Make(
911*c8dee2aaSAndroid Build Coastguard Worker std::move(strikePromise), get_packedIDs(accepted), alloc);
912*c8dee2aaSAndroid Build Coastguard Worker
913*c8dee2aaSAndroid Build Coastguard Worker return alloc->makeUnique<TransformedMaskSubRun>(
914*c8dee2aaSAndroid Build Coastguard Worker initialPositionMatrix.getMaxScale() >= 1,
915*c8dee2aaSAndroid Build Coastguard Worker std::move(vertexFiller),
916*c8dee2aaSAndroid Build Coastguard Worker std::move(glyphVector));
917*c8dee2aaSAndroid Build Coastguard Worker }
918*c8dee2aaSAndroid Build Coastguard Worker
MakeFromBuffer(SkReadBuffer & buffer,SubRunAllocator * alloc,const SkStrikeClient * client)919*c8dee2aaSAndroid Build Coastguard Worker static SubRunOwner MakeFromBuffer(SkReadBuffer& buffer,
920*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc,
921*c8dee2aaSAndroid Build Coastguard Worker const SkStrikeClient* client) {
922*c8dee2aaSAndroid Build Coastguard Worker auto vertexFiller = VertexFiller::MakeFromBuffer(buffer, alloc);
923*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(vertexFiller.has_value())) { return nullptr; }
924*c8dee2aaSAndroid Build Coastguard Worker
925*c8dee2aaSAndroid Build Coastguard Worker auto glyphVector = GlyphVector::MakeFromBuffer(buffer, client, alloc);
926*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(glyphVector.has_value())) { return nullptr; }
927*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(SkCount(glyphVector->glyphs()) == vertexFiller->count())) {
928*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
929*c8dee2aaSAndroid Build Coastguard Worker }
930*c8dee2aaSAndroid Build Coastguard Worker const bool isBigEnough = buffer.readBool();
931*c8dee2aaSAndroid Build Coastguard Worker return alloc->makeUnique<TransformedMaskSubRun>(
932*c8dee2aaSAndroid Build Coastguard Worker isBigEnough, std::move(*vertexFiller), std::move(*glyphVector));
933*c8dee2aaSAndroid Build Coastguard Worker }
934*c8dee2aaSAndroid Build Coastguard Worker
unflattenSize() const935*c8dee2aaSAndroid Build Coastguard Worker int unflattenSize() const override {
936*c8dee2aaSAndroid Build Coastguard Worker return sizeof(TransformedMaskSubRun) +
937*c8dee2aaSAndroid Build Coastguard Worker fGlyphs.unflattenSize() +
938*c8dee2aaSAndroid Build Coastguard Worker fVertexFiller.unflattenSize();
939*c8dee2aaSAndroid Build Coastguard Worker }
940*c8dee2aaSAndroid Build Coastguard Worker
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const941*c8dee2aaSAndroid Build Coastguard Worker bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const override {
942*c8dee2aaSAndroid Build Coastguard Worker // If we are not scaling the cache entry to be larger, than a cache with smaller glyphs may
943*c8dee2aaSAndroid Build Coastguard Worker // be better.
944*c8dee2aaSAndroid Build Coastguard Worker return fIsBigEnough;
945*c8dee2aaSAndroid Build Coastguard Worker }
946*c8dee2aaSAndroid Build Coastguard Worker
testingOnly_atlasSubRun() const947*c8dee2aaSAndroid Build Coastguard Worker const AtlasSubRun* testingOnly_atlasSubRun() const override { return this; }
948*c8dee2aaSAndroid Build Coastguard Worker
testingOnly_packedGlyphIDToGlyph(StrikeCache * cache) const949*c8dee2aaSAndroid Build Coastguard Worker void testingOnly_packedGlyphIDToGlyph(StrikeCache *cache) const override {
950*c8dee2aaSAndroid Build Coastguard Worker fGlyphs.packedGlyphIDToGlyph(cache);
951*c8dee2aaSAndroid Build Coastguard Worker }
952*c8dee2aaSAndroid Build Coastguard Worker
glyphCount() const953*c8dee2aaSAndroid Build Coastguard Worker int glyphCount() const override { return SkCount(fGlyphs.glyphs()); }
954*c8dee2aaSAndroid Build Coastguard Worker
glyphs() const955*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const Glyph*> glyphs() const override {
956*c8dee2aaSAndroid Build Coastguard Worker return fGlyphs.glyphs();
957*c8dee2aaSAndroid Build Coastguard Worker }
958*c8dee2aaSAndroid Build Coastguard Worker
instanceFlags() const959*c8dee2aaSAndroid Build Coastguard Worker unsigned short instanceFlags() const override {
960*c8dee2aaSAndroid Build Coastguard Worker return (unsigned short)fVertexFiller.grMaskType();
961*c8dee2aaSAndroid Build Coastguard Worker }
962*c8dee2aaSAndroid Build Coastguard Worker
maskFormat() const963*c8dee2aaSAndroid Build Coastguard Worker MaskFormat maskFormat() const override { return fVertexFiller.grMaskType(); }
964*c8dee2aaSAndroid Build Coastguard Worker
glyphSrcPadding() const965*c8dee2aaSAndroid Build Coastguard Worker int glyphSrcPadding() const override { return 1; }
966*c8dee2aaSAndroid Build Coastguard Worker
draw(SkCanvas *,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> subRunStorage,const AtlasDrawDelegate & drawAtlas) const967*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas*,
968*c8dee2aaSAndroid Build Coastguard Worker SkPoint drawOrigin,
969*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint,
970*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRefCnt> subRunStorage,
971*c8dee2aaSAndroid Build Coastguard Worker const AtlasDrawDelegate& drawAtlas) const override {
972*c8dee2aaSAndroid Build Coastguard Worker drawAtlas(this, drawOrigin, paint, std::move(subRunStorage),
973*c8dee2aaSAndroid Build Coastguard Worker {/* isSDF = */false, fVertexFiller.isLCD(), fVertexFiller.grMaskType()});
974*c8dee2aaSAndroid Build Coastguard Worker }
975*c8dee2aaSAndroid Build Coastguard Worker
976*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
977*c8dee2aaSAndroid Build Coastguard Worker
vertexStride(const SkMatrix & drawMatrix) const978*c8dee2aaSAndroid Build Coastguard Worker size_t vertexStride(const SkMatrix& drawMatrix) const override {
979*c8dee2aaSAndroid Build Coastguard Worker return fVertexFiller.vertexStride(drawMatrix);
980*c8dee2aaSAndroid Build Coastguard Worker }
981*c8dee2aaSAndroid Build Coastguard Worker
makeAtlasTextOp(const GrClip * clip,const SkMatrix & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> && subRunStorage,skgpu::ganesh::SurfaceDrawContext * sdc) const982*c8dee2aaSAndroid Build Coastguard Worker std::tuple<const GrClip*, GrOp::Owner> makeAtlasTextOp(
983*c8dee2aaSAndroid Build Coastguard Worker const GrClip* clip,
984*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& viewMatrix,
985*c8dee2aaSAndroid Build Coastguard Worker SkPoint drawOrigin,
986*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint,
987*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRefCnt>&& subRunStorage,
988*c8dee2aaSAndroid Build Coastguard Worker skgpu::ganesh::SurfaceDrawContext* sdc) const override {
989*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->glyphCount() != 0);
990*c8dee2aaSAndroid Build Coastguard Worker
991*c8dee2aaSAndroid Build Coastguard Worker GrPaint grPaint;
992*c8dee2aaSAndroid Build Coastguard Worker SkPMColor4f drawingColor = calculate_colors(sdc,
993*c8dee2aaSAndroid Build Coastguard Worker paint,
994*c8dee2aaSAndroid Build Coastguard Worker viewMatrix,
995*c8dee2aaSAndroid Build Coastguard Worker fVertexFiller.grMaskType(),
996*c8dee2aaSAndroid Build Coastguard Worker &grPaint);
997*c8dee2aaSAndroid Build Coastguard Worker
998*c8dee2aaSAndroid Build Coastguard Worker auto geometry = AtlasTextOp::Geometry::Make(*this,
999*c8dee2aaSAndroid Build Coastguard Worker viewMatrix,
1000*c8dee2aaSAndroid Build Coastguard Worker drawOrigin,
1001*c8dee2aaSAndroid Build Coastguard Worker SkIRect::MakeEmpty(),
1002*c8dee2aaSAndroid Build Coastguard Worker std::move(subRunStorage),
1003*c8dee2aaSAndroid Build Coastguard Worker drawingColor,
1004*c8dee2aaSAndroid Build Coastguard Worker sdc->arenaAlloc());
1005*c8dee2aaSAndroid Build Coastguard Worker
1006*c8dee2aaSAndroid Build Coastguard Worker GrRecordingContext* const rContext = sdc->recordingContext();
1007*c8dee2aaSAndroid Build Coastguard Worker SkMatrix positionMatrix = position_matrix(viewMatrix, drawOrigin);
1008*c8dee2aaSAndroid Build Coastguard Worker auto [_, deviceRect] = fVertexFiller.deviceRectAndCheckTransform(positionMatrix);
1009*c8dee2aaSAndroid Build Coastguard Worker GrOp::Owner op = GrOp::Make<AtlasTextOp>(rContext,
1010*c8dee2aaSAndroid Build Coastguard Worker fVertexFiller.opMaskType(),
1011*c8dee2aaSAndroid Build Coastguard Worker true,
1012*c8dee2aaSAndroid Build Coastguard Worker this->glyphCount(),
1013*c8dee2aaSAndroid Build Coastguard Worker deviceRect,
1014*c8dee2aaSAndroid Build Coastguard Worker geometry,
1015*c8dee2aaSAndroid Build Coastguard Worker sdc->colorInfo(),
1016*c8dee2aaSAndroid Build Coastguard Worker std::move(grPaint));
1017*c8dee2aaSAndroid Build Coastguard Worker return {clip, std::move(op)};
1018*c8dee2aaSAndroid Build Coastguard Worker }
1019*c8dee2aaSAndroid Build Coastguard Worker
fillVertexData(void * vertexDst,int offset,int count,GrColor color,const SkMatrix & drawMatrix,SkPoint drawOrigin,SkIRect clip) const1020*c8dee2aaSAndroid Build Coastguard Worker void fillVertexData(
1021*c8dee2aaSAndroid Build Coastguard Worker void* vertexDst, int offset, int count,
1022*c8dee2aaSAndroid Build Coastguard Worker GrColor color,
1023*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& drawMatrix, SkPoint drawOrigin,
1024*c8dee2aaSAndroid Build Coastguard Worker SkIRect clip) const override {
1025*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix positionMatrix = position_matrix(drawMatrix, drawOrigin);
1026*c8dee2aaSAndroid Build Coastguard Worker fVertexFiller.fillVertexData(offset, count,
1027*c8dee2aaSAndroid Build Coastguard Worker fGlyphs.glyphs(),
1028*c8dee2aaSAndroid Build Coastguard Worker color,
1029*c8dee2aaSAndroid Build Coastguard Worker positionMatrix,
1030*c8dee2aaSAndroid Build Coastguard Worker clip,
1031*c8dee2aaSAndroid Build Coastguard Worker vertexDst);
1032*c8dee2aaSAndroid Build Coastguard Worker }
1033*c8dee2aaSAndroid Build Coastguard Worker #endif // defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
1034*c8dee2aaSAndroid Build Coastguard Worker
regenerateAtlas(int begin,int end,RegenerateAtlasDelegate regenerateAtlas) const1035*c8dee2aaSAndroid Build Coastguard Worker std::tuple<bool, int> regenerateAtlas(int begin, int end,
1036*c8dee2aaSAndroid Build Coastguard Worker RegenerateAtlasDelegate regenerateAtlas) const override {
1037*c8dee2aaSAndroid Build Coastguard Worker return regenerateAtlas(
1038*c8dee2aaSAndroid Build Coastguard Worker &fGlyphs, begin, end, fVertexFiller.grMaskType(), this->glyphSrcPadding());
1039*c8dee2aaSAndroid Build Coastguard Worker }
1040*c8dee2aaSAndroid Build Coastguard Worker
vertexFiller() const1041*c8dee2aaSAndroid Build Coastguard Worker const VertexFiller& vertexFiller() const override { return fVertexFiller; }
1042*c8dee2aaSAndroid Build Coastguard Worker
1043*c8dee2aaSAndroid Build Coastguard Worker protected:
subRunStreamTag() const1044*c8dee2aaSAndroid Build Coastguard Worker SubRunStreamTag subRunStreamTag() const override {
1045*c8dee2aaSAndroid Build Coastguard Worker return SubRunStreamTag::kTransformMaskStreamTag;
1046*c8dee2aaSAndroid Build Coastguard Worker }
1047*c8dee2aaSAndroid Build Coastguard Worker
doFlatten(SkWriteBuffer & buffer) const1048*c8dee2aaSAndroid Build Coastguard Worker void doFlatten(SkWriteBuffer& buffer) const override {
1049*c8dee2aaSAndroid Build Coastguard Worker fVertexFiller.flatten(buffer);
1050*c8dee2aaSAndroid Build Coastguard Worker fGlyphs.flatten(buffer);
1051*c8dee2aaSAndroid Build Coastguard Worker buffer.writeBool(fIsBigEnough);
1052*c8dee2aaSAndroid Build Coastguard Worker }
1053*c8dee2aaSAndroid Build Coastguard Worker
1054*c8dee2aaSAndroid Build Coastguard Worker private:
1055*c8dee2aaSAndroid Build Coastguard Worker const bool fIsBigEnough;
1056*c8dee2aaSAndroid Build Coastguard Worker
1057*c8dee2aaSAndroid Build Coastguard Worker const VertexFiller fVertexFiller;
1058*c8dee2aaSAndroid Build Coastguard Worker
1059*c8dee2aaSAndroid Build Coastguard Worker // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
1060*c8dee2aaSAndroid Build Coastguard Worker // be single threaded.
1061*c8dee2aaSAndroid Build Coastguard Worker mutable GlyphVector fGlyphs;
1062*c8dee2aaSAndroid Build Coastguard Worker }; // class TransformedMaskSubRun
1063*c8dee2aaSAndroid Build Coastguard Worker
1064*c8dee2aaSAndroid Build Coastguard Worker // -- SDFTSubRun -----------------------------------------------------------------------------------
1065*c8dee2aaSAndroid Build Coastguard Worker
has_some_antialiasing(const SkFont & font)1066*c8dee2aaSAndroid Build Coastguard Worker bool has_some_antialiasing(const SkFont& font ) {
1067*c8dee2aaSAndroid Build Coastguard Worker SkFont::Edging edging = font.getEdging();
1068*c8dee2aaSAndroid Build Coastguard Worker return edging == SkFont::Edging::kAntiAlias
1069*c8dee2aaSAndroid Build Coastguard Worker || edging == SkFont::Edging::kSubpixelAntiAlias;
1070*c8dee2aaSAndroid Build Coastguard Worker }
1071*c8dee2aaSAndroid Build Coastguard Worker
1072*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_DISABLE_SDF_TEXT)
1073*c8dee2aaSAndroid Build Coastguard Worker
1074*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
1075*c8dee2aaSAndroid Build Coastguard Worker
calculate_sdf_parameters(const skgpu::ganesh::SurfaceDrawContext & sdc,const SkMatrix & drawMatrix,bool useLCDText,bool isAntiAliased)1076*c8dee2aaSAndroid Build Coastguard Worker static std::tuple<AtlasTextOp::MaskType, uint32_t, bool> calculate_sdf_parameters(
1077*c8dee2aaSAndroid Build Coastguard Worker const skgpu::ganesh::SurfaceDrawContext& sdc,
1078*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& drawMatrix,
1079*c8dee2aaSAndroid Build Coastguard Worker bool useLCDText,
1080*c8dee2aaSAndroid Build Coastguard Worker bool isAntiAliased) {
1081*c8dee2aaSAndroid Build Coastguard Worker const GrColorInfo& colorInfo = sdc.colorInfo();
1082*c8dee2aaSAndroid Build Coastguard Worker const SkSurfaceProps& props = sdc.surfaceProps();
1083*c8dee2aaSAndroid Build Coastguard Worker using MT = AtlasTextOp::MaskType;
1084*c8dee2aaSAndroid Build Coastguard Worker bool isLCD = useLCDText && props.pixelGeometry() != kUnknown_SkPixelGeometry;
1085*c8dee2aaSAndroid Build Coastguard Worker MT maskType = !isAntiAliased ? MT::kAliasedDistanceField
1086*c8dee2aaSAndroid Build Coastguard Worker : isLCD ? MT::kLCDDistanceField
1087*c8dee2aaSAndroid Build Coastguard Worker : MT::kGrayscaleDistanceField;
1088*c8dee2aaSAndroid Build Coastguard Worker
1089*c8dee2aaSAndroid Build Coastguard Worker bool useGammaCorrectDistanceTable = colorInfo.isLinearlyBlended();
1090*c8dee2aaSAndroid Build Coastguard Worker uint32_t DFGPFlags = drawMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
1091*c8dee2aaSAndroid Build Coastguard Worker DFGPFlags |= drawMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
1092*c8dee2aaSAndroid Build Coastguard Worker DFGPFlags |= useGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;
1093*c8dee2aaSAndroid Build Coastguard Worker DFGPFlags |= MT::kAliasedDistanceField == maskType ? kAliased_DistanceFieldEffectFlag : 0;
1094*c8dee2aaSAndroid Build Coastguard Worker DFGPFlags |= drawMatrix.hasPerspective() ? kPerspective_DistanceFieldEffectFlag : 0;
1095*c8dee2aaSAndroid Build Coastguard Worker
1096*c8dee2aaSAndroid Build Coastguard Worker if (isLCD) {
1097*c8dee2aaSAndroid Build Coastguard Worker bool isBGR = SkPixelGeometryIsBGR(props.pixelGeometry());
1098*c8dee2aaSAndroid Build Coastguard Worker bool isVertical = SkPixelGeometryIsV(props.pixelGeometry());
1099*c8dee2aaSAndroid Build Coastguard Worker DFGPFlags |= kUseLCD_DistanceFieldEffectFlag;
1100*c8dee2aaSAndroid Build Coastguard Worker DFGPFlags |= isBGR ? kBGR_DistanceFieldEffectFlag : 0;
1101*c8dee2aaSAndroid Build Coastguard Worker DFGPFlags |= isVertical ? kPortrait_DistanceFieldEffectFlag : 0;
1102*c8dee2aaSAndroid Build Coastguard Worker }
1103*c8dee2aaSAndroid Build Coastguard Worker return {maskType, DFGPFlags, useGammaCorrectDistanceTable};
1104*c8dee2aaSAndroid Build Coastguard Worker }
1105*c8dee2aaSAndroid Build Coastguard Worker
1106*c8dee2aaSAndroid Build Coastguard Worker #endif // defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
1107*c8dee2aaSAndroid Build Coastguard Worker
1108*c8dee2aaSAndroid Build Coastguard Worker class SDFTSubRun final : public SubRun, public AtlasSubRun {
1109*c8dee2aaSAndroid Build Coastguard Worker public:
SDFTSubRun(bool useLCDText,bool antiAliased,const SDFTMatrixRange & matrixRange,VertexFiller && vertexFiller,GlyphVector && glyphs)1110*c8dee2aaSAndroid Build Coastguard Worker SDFTSubRun(bool useLCDText,
1111*c8dee2aaSAndroid Build Coastguard Worker bool antiAliased,
1112*c8dee2aaSAndroid Build Coastguard Worker const SDFTMatrixRange& matrixRange,
1113*c8dee2aaSAndroid Build Coastguard Worker VertexFiller&& vertexFiller,
1114*c8dee2aaSAndroid Build Coastguard Worker GlyphVector&& glyphs)
1115*c8dee2aaSAndroid Build Coastguard Worker : fUseLCDText{useLCDText}
1116*c8dee2aaSAndroid Build Coastguard Worker , fAntiAliased{antiAliased}
1117*c8dee2aaSAndroid Build Coastguard Worker , fMatrixRange{matrixRange}
1118*c8dee2aaSAndroid Build Coastguard Worker , fVertexFiller{std::move(vertexFiller)}
1119*c8dee2aaSAndroid Build Coastguard Worker , fGlyphs{std::move(glyphs)} { }
1120*c8dee2aaSAndroid Build Coastguard Worker
Make(SkZip<const SkPackedGlyphID,const SkPoint> accepted,const SkFont & runFont,SkStrikePromise && strikePromise,const SkMatrix & creationMatrix,SkRect creationBounds,const SDFTMatrixRange & matrixRange,SubRunAllocator * alloc)1121*c8dee2aaSAndroid Build Coastguard Worker static SubRunOwner Make(SkZip<const SkPackedGlyphID, const SkPoint> accepted,
1122*c8dee2aaSAndroid Build Coastguard Worker const SkFont& runFont,
1123*c8dee2aaSAndroid Build Coastguard Worker SkStrikePromise&& strikePromise,
1124*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& creationMatrix,
1125*c8dee2aaSAndroid Build Coastguard Worker SkRect creationBounds,
1126*c8dee2aaSAndroid Build Coastguard Worker const SDFTMatrixRange& matrixRange,
1127*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc) {
1128*c8dee2aaSAndroid Build Coastguard Worker auto vertexFiller = VertexFiller::Make(MaskFormat::kA8,
1129*c8dee2aaSAndroid Build Coastguard Worker creationMatrix,
1130*c8dee2aaSAndroid Build Coastguard Worker creationBounds,
1131*c8dee2aaSAndroid Build Coastguard Worker get_positions(accepted),
1132*c8dee2aaSAndroid Build Coastguard Worker alloc,
1133*c8dee2aaSAndroid Build Coastguard Worker kIsTransformed);
1134*c8dee2aaSAndroid Build Coastguard Worker
1135*c8dee2aaSAndroid Build Coastguard Worker auto glyphVector = GlyphVector::Make(
1136*c8dee2aaSAndroid Build Coastguard Worker std::move(strikePromise), get_packedIDs(accepted), alloc);
1137*c8dee2aaSAndroid Build Coastguard Worker
1138*c8dee2aaSAndroid Build Coastguard Worker return alloc->makeUnique<SDFTSubRun>(
1139*c8dee2aaSAndroid Build Coastguard Worker runFont.getEdging() == SkFont::Edging::kSubpixelAntiAlias,
1140*c8dee2aaSAndroid Build Coastguard Worker has_some_antialiasing(runFont),
1141*c8dee2aaSAndroid Build Coastguard Worker matrixRange,
1142*c8dee2aaSAndroid Build Coastguard Worker std::move(vertexFiller),
1143*c8dee2aaSAndroid Build Coastguard Worker std::move(glyphVector));
1144*c8dee2aaSAndroid Build Coastguard Worker }
1145*c8dee2aaSAndroid Build Coastguard Worker
MakeFromBuffer(SkReadBuffer & buffer,SubRunAllocator * alloc,const SkStrikeClient * client)1146*c8dee2aaSAndroid Build Coastguard Worker static SubRunOwner MakeFromBuffer(SkReadBuffer& buffer,
1147*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc,
1148*c8dee2aaSAndroid Build Coastguard Worker const SkStrikeClient* client) {
1149*c8dee2aaSAndroid Build Coastguard Worker int useLCD = buffer.readInt();
1150*c8dee2aaSAndroid Build Coastguard Worker int isAntiAliased = buffer.readInt();
1151*c8dee2aaSAndroid Build Coastguard Worker SDFTMatrixRange matrixRange = SDFTMatrixRange::MakeFromBuffer(buffer);
1152*c8dee2aaSAndroid Build Coastguard Worker auto vertexFiller = VertexFiller::MakeFromBuffer(buffer, alloc);
1153*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(vertexFiller.has_value())) { return nullptr; }
1154*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(vertexFiller.value().grMaskType() == MaskFormat::kA8)) {
1155*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
1156*c8dee2aaSAndroid Build Coastguard Worker }
1157*c8dee2aaSAndroid Build Coastguard Worker auto glyphVector = GlyphVector::MakeFromBuffer(buffer, client, alloc);
1158*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(glyphVector.has_value())) { return nullptr; }
1159*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(SkCount(glyphVector->glyphs()) == vertexFiller->count())) {
1160*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
1161*c8dee2aaSAndroid Build Coastguard Worker }
1162*c8dee2aaSAndroid Build Coastguard Worker return alloc->makeUnique<SDFTSubRun>(useLCD,
1163*c8dee2aaSAndroid Build Coastguard Worker isAntiAliased,
1164*c8dee2aaSAndroid Build Coastguard Worker matrixRange,
1165*c8dee2aaSAndroid Build Coastguard Worker std::move(*vertexFiller),
1166*c8dee2aaSAndroid Build Coastguard Worker std::move(*glyphVector));
1167*c8dee2aaSAndroid Build Coastguard Worker }
1168*c8dee2aaSAndroid Build Coastguard Worker
unflattenSize() const1169*c8dee2aaSAndroid Build Coastguard Worker int unflattenSize() const override {
1170*c8dee2aaSAndroid Build Coastguard Worker return sizeof(SDFTSubRun) + fGlyphs.unflattenSize() + fVertexFiller.unflattenSize();
1171*c8dee2aaSAndroid Build Coastguard Worker }
1172*c8dee2aaSAndroid Build Coastguard Worker
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const1173*c8dee2aaSAndroid Build Coastguard Worker bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const override {
1174*c8dee2aaSAndroid Build Coastguard Worker return fMatrixRange.matrixInRange(positionMatrix);
1175*c8dee2aaSAndroid Build Coastguard Worker }
1176*c8dee2aaSAndroid Build Coastguard Worker
testingOnly_atlasSubRun() const1177*c8dee2aaSAndroid Build Coastguard Worker const AtlasSubRun* testingOnly_atlasSubRun() const override { return this; }
1178*c8dee2aaSAndroid Build Coastguard Worker
testingOnly_packedGlyphIDToGlyph(StrikeCache * cache) const1179*c8dee2aaSAndroid Build Coastguard Worker void testingOnly_packedGlyphIDToGlyph(StrikeCache *cache) const override {
1180*c8dee2aaSAndroid Build Coastguard Worker fGlyphs.packedGlyphIDToGlyph(cache);
1181*c8dee2aaSAndroid Build Coastguard Worker }
1182*c8dee2aaSAndroid Build Coastguard Worker
glyphCount() const1183*c8dee2aaSAndroid Build Coastguard Worker int glyphCount() const override { return fVertexFiller.count(); }
maskFormat() const1184*c8dee2aaSAndroid Build Coastguard Worker MaskFormat maskFormat() const override {
1185*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fVertexFiller.grMaskType() == MaskFormat::kA8);
1186*c8dee2aaSAndroid Build Coastguard Worker return MaskFormat::kA8;
1187*c8dee2aaSAndroid Build Coastguard Worker }
glyphSrcPadding() const1188*c8dee2aaSAndroid Build Coastguard Worker int glyphSrcPadding() const override { return SK_DistanceFieldInset; }
1189*c8dee2aaSAndroid Build Coastguard Worker
glyphs() const1190*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const Glyph*> glyphs() const override {
1191*c8dee2aaSAndroid Build Coastguard Worker return fGlyphs.glyphs();
1192*c8dee2aaSAndroid Build Coastguard Worker }
1193*c8dee2aaSAndroid Build Coastguard Worker
instanceFlags() const1194*c8dee2aaSAndroid Build Coastguard Worker unsigned short instanceFlags() const override {
1195*c8dee2aaSAndroid Build Coastguard Worker return (unsigned short)MaskFormat::kA8;
1196*c8dee2aaSAndroid Build Coastguard Worker }
1197*c8dee2aaSAndroid Build Coastguard Worker
draw(SkCanvas *,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> subRunStorage,const AtlasDrawDelegate & drawAtlas) const1198*c8dee2aaSAndroid Build Coastguard Worker void draw(SkCanvas*,
1199*c8dee2aaSAndroid Build Coastguard Worker SkPoint drawOrigin,
1200*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint,
1201*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRefCnt> subRunStorage,
1202*c8dee2aaSAndroid Build Coastguard Worker const AtlasDrawDelegate& drawAtlas) const override {
1203*c8dee2aaSAndroid Build Coastguard Worker drawAtlas(this, drawOrigin, paint, std::move(subRunStorage),
1204*c8dee2aaSAndroid Build Coastguard Worker {/* isSDF = */true, /* isLCD = */fUseLCDText, skgpu::MaskFormat::kA8});
1205*c8dee2aaSAndroid Build Coastguard Worker }
1206*c8dee2aaSAndroid Build Coastguard Worker
1207*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
vertexStride(const SkMatrix & drawMatrix) const1208*c8dee2aaSAndroid Build Coastguard Worker size_t vertexStride(const SkMatrix& drawMatrix) const override {
1209*c8dee2aaSAndroid Build Coastguard Worker return fVertexFiller.vertexStride(drawMatrix);
1210*c8dee2aaSAndroid Build Coastguard Worker }
1211*c8dee2aaSAndroid Build Coastguard Worker
makeAtlasTextOp(const GrClip * clip,const SkMatrix & viewMatrix,SkPoint drawOrigin,const SkPaint & paint,sk_sp<SkRefCnt> && subRunStorage,skgpu::ganesh::SurfaceDrawContext * sdc) const1212*c8dee2aaSAndroid Build Coastguard Worker std::tuple<const GrClip*, GrOp::Owner> makeAtlasTextOp(
1213*c8dee2aaSAndroid Build Coastguard Worker const GrClip* clip,
1214*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& viewMatrix,
1215*c8dee2aaSAndroid Build Coastguard Worker SkPoint drawOrigin,
1216*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint,
1217*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRefCnt>&& subRunStorage,
1218*c8dee2aaSAndroid Build Coastguard Worker skgpu::ganesh::SurfaceDrawContext* sdc) const override {
1219*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->glyphCount() != 0);
1220*c8dee2aaSAndroid Build Coastguard Worker
1221*c8dee2aaSAndroid Build Coastguard Worker GrPaint grPaint;
1222*c8dee2aaSAndroid Build Coastguard Worker SkPMColor4f drawingColor = calculate_colors(sdc,
1223*c8dee2aaSAndroid Build Coastguard Worker paint,
1224*c8dee2aaSAndroid Build Coastguard Worker viewMatrix,
1225*c8dee2aaSAndroid Build Coastguard Worker MaskFormat::kA8,
1226*c8dee2aaSAndroid Build Coastguard Worker &grPaint);
1227*c8dee2aaSAndroid Build Coastguard Worker
1228*c8dee2aaSAndroid Build Coastguard Worker auto [maskType, DFGPFlags, useGammaCorrectDistanceTable] =
1229*c8dee2aaSAndroid Build Coastguard Worker calculate_sdf_parameters(*sdc, viewMatrix, fUseLCDText, fAntiAliased);
1230*c8dee2aaSAndroid Build Coastguard Worker
1231*c8dee2aaSAndroid Build Coastguard Worker auto geometry = AtlasTextOp::Geometry::Make(*this,
1232*c8dee2aaSAndroid Build Coastguard Worker viewMatrix,
1233*c8dee2aaSAndroid Build Coastguard Worker drawOrigin,
1234*c8dee2aaSAndroid Build Coastguard Worker SkIRect::MakeEmpty(),
1235*c8dee2aaSAndroid Build Coastguard Worker std::move(subRunStorage),
1236*c8dee2aaSAndroid Build Coastguard Worker drawingColor,
1237*c8dee2aaSAndroid Build Coastguard Worker sdc->arenaAlloc());
1238*c8dee2aaSAndroid Build Coastguard Worker
1239*c8dee2aaSAndroid Build Coastguard Worker GrRecordingContext* const rContext = sdc->recordingContext();
1240*c8dee2aaSAndroid Build Coastguard Worker SkMatrix positionMatrix = position_matrix(viewMatrix, drawOrigin);
1241*c8dee2aaSAndroid Build Coastguard Worker auto [_, deviceRect] = fVertexFiller.deviceRectAndCheckTransform(positionMatrix);
1242*c8dee2aaSAndroid Build Coastguard Worker GrOp::Owner op = GrOp::Make<AtlasTextOp>(rContext,
1243*c8dee2aaSAndroid Build Coastguard Worker maskType,
1244*c8dee2aaSAndroid Build Coastguard Worker true,
1245*c8dee2aaSAndroid Build Coastguard Worker this->glyphCount(),
1246*c8dee2aaSAndroid Build Coastguard Worker deviceRect,
1247*c8dee2aaSAndroid Build Coastguard Worker SkPaintPriv::ComputeLuminanceColor(paint),
1248*c8dee2aaSAndroid Build Coastguard Worker useGammaCorrectDistanceTable,
1249*c8dee2aaSAndroid Build Coastguard Worker DFGPFlags,
1250*c8dee2aaSAndroid Build Coastguard Worker geometry,
1251*c8dee2aaSAndroid Build Coastguard Worker std::move(grPaint));
1252*c8dee2aaSAndroid Build Coastguard Worker
1253*c8dee2aaSAndroid Build Coastguard Worker return {clip, std::move(op)};
1254*c8dee2aaSAndroid Build Coastguard Worker }
1255*c8dee2aaSAndroid Build Coastguard Worker
fillVertexData(void * vertexDst,int offset,int count,GrColor color,const SkMatrix & drawMatrix,SkPoint drawOrigin,SkIRect clip) const1256*c8dee2aaSAndroid Build Coastguard Worker void fillVertexData(
1257*c8dee2aaSAndroid Build Coastguard Worker void *vertexDst, int offset, int count,
1258*c8dee2aaSAndroid Build Coastguard Worker GrColor color,
1259*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& drawMatrix, SkPoint drawOrigin,
1260*c8dee2aaSAndroid Build Coastguard Worker SkIRect clip) const override {
1261*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix positionMatrix = position_matrix(drawMatrix, drawOrigin);
1262*c8dee2aaSAndroid Build Coastguard Worker
1263*c8dee2aaSAndroid Build Coastguard Worker fVertexFiller.fillVertexData(offset, count,
1264*c8dee2aaSAndroid Build Coastguard Worker fGlyphs.glyphs(),
1265*c8dee2aaSAndroid Build Coastguard Worker color,
1266*c8dee2aaSAndroid Build Coastguard Worker positionMatrix,
1267*c8dee2aaSAndroid Build Coastguard Worker clip,
1268*c8dee2aaSAndroid Build Coastguard Worker vertexDst);
1269*c8dee2aaSAndroid Build Coastguard Worker }
1270*c8dee2aaSAndroid Build Coastguard Worker
1271*c8dee2aaSAndroid Build Coastguard Worker #endif // defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
1272*c8dee2aaSAndroid Build Coastguard Worker
regenerateAtlas(int begin,int end,RegenerateAtlasDelegate regenerateAtlas) const1273*c8dee2aaSAndroid Build Coastguard Worker std::tuple<bool, int> regenerateAtlas(int begin, int end,
1274*c8dee2aaSAndroid Build Coastguard Worker RegenerateAtlasDelegate regenerateAtlas) const override {
1275*c8dee2aaSAndroid Build Coastguard Worker return regenerateAtlas(&fGlyphs, begin, end, MaskFormat::kA8, this->glyphSrcPadding());
1276*c8dee2aaSAndroid Build Coastguard Worker }
1277*c8dee2aaSAndroid Build Coastguard Worker
vertexFiller() const1278*c8dee2aaSAndroid Build Coastguard Worker const VertexFiller& vertexFiller() const override { return fVertexFiller; }
1279*c8dee2aaSAndroid Build Coastguard Worker
1280*c8dee2aaSAndroid Build Coastguard Worker protected:
subRunStreamTag() const1281*c8dee2aaSAndroid Build Coastguard Worker SubRunStreamTag subRunStreamTag() const override { return SubRunStreamTag::kSDFTStreamTag; }
doFlatten(SkWriteBuffer & buffer) const1282*c8dee2aaSAndroid Build Coastguard Worker void doFlatten(SkWriteBuffer& buffer) const override {
1283*c8dee2aaSAndroid Build Coastguard Worker buffer.writeInt(fUseLCDText);
1284*c8dee2aaSAndroid Build Coastguard Worker buffer.writeInt(fAntiAliased);
1285*c8dee2aaSAndroid Build Coastguard Worker fMatrixRange.flatten(buffer);
1286*c8dee2aaSAndroid Build Coastguard Worker fVertexFiller.flatten(buffer);
1287*c8dee2aaSAndroid Build Coastguard Worker fGlyphs.flatten(buffer);
1288*c8dee2aaSAndroid Build Coastguard Worker }
1289*c8dee2aaSAndroid Build Coastguard Worker
1290*c8dee2aaSAndroid Build Coastguard Worker private:
1291*c8dee2aaSAndroid Build Coastguard Worker const bool fUseLCDText;
1292*c8dee2aaSAndroid Build Coastguard Worker const bool fAntiAliased;
1293*c8dee2aaSAndroid Build Coastguard Worker const SDFTMatrixRange fMatrixRange;
1294*c8dee2aaSAndroid Build Coastguard Worker
1295*c8dee2aaSAndroid Build Coastguard Worker const VertexFiller fVertexFiller;
1296*c8dee2aaSAndroid Build Coastguard Worker
1297*c8dee2aaSAndroid Build Coastguard Worker // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must
1298*c8dee2aaSAndroid Build Coastguard Worker // be single threaded.
1299*c8dee2aaSAndroid Build Coastguard Worker mutable GlyphVector fGlyphs;
1300*c8dee2aaSAndroid Build Coastguard Worker }; // class SDFTSubRun
1301*c8dee2aaSAndroid Build Coastguard Worker
1302*c8dee2aaSAndroid Build Coastguard Worker #endif // !defined(SK_DISABLE_SDF_TEXT)
1303*c8dee2aaSAndroid Build Coastguard Worker
1304*c8dee2aaSAndroid Build Coastguard Worker // -- SubRun ---------------------------------------------------------------------------------------
1305*c8dee2aaSAndroid Build Coastguard Worker
1306*c8dee2aaSAndroid Build Coastguard Worker template<typename AddSingleMaskFormat>
add_multi_mask_format(AddSingleMaskFormat addSingleMaskFormat,SkZip<const SkPackedGlyphID,const SkPoint,const SkMask::Format> accepted)1307*c8dee2aaSAndroid Build Coastguard Worker void add_multi_mask_format(
1308*c8dee2aaSAndroid Build Coastguard Worker AddSingleMaskFormat addSingleMaskFormat,
1309*c8dee2aaSAndroid Build Coastguard Worker SkZip<const SkPackedGlyphID, const SkPoint, const SkMask::Format> accepted) {
1310*c8dee2aaSAndroid Build Coastguard Worker if (accepted.empty()) { return; }
1311*c8dee2aaSAndroid Build Coastguard Worker
1312*c8dee2aaSAndroid Build Coastguard Worker auto maskSpan = accepted.get<2>();
1313*c8dee2aaSAndroid Build Coastguard Worker MaskFormat format = Glyph::FormatFromSkGlyph(maskSpan[0]);
1314*c8dee2aaSAndroid Build Coastguard Worker size_t startIndex = 0;
1315*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 1; i < accepted.size(); i++) {
1316*c8dee2aaSAndroid Build Coastguard Worker MaskFormat nextFormat = Glyph::FormatFromSkGlyph(maskSpan[i]);
1317*c8dee2aaSAndroid Build Coastguard Worker if (format != nextFormat) {
1318*c8dee2aaSAndroid Build Coastguard Worker auto interval = accepted.subspan(startIndex, i - startIndex);
1319*c8dee2aaSAndroid Build Coastguard Worker // Only pass the packed glyph ids and positions.
1320*c8dee2aaSAndroid Build Coastguard Worker auto glyphsWithSameFormat = SkMakeZip(interval.get<0>(), interval.get<1>());
1321*c8dee2aaSAndroid Build Coastguard Worker // Take a ref on the strike. This should rarely happen.
1322*c8dee2aaSAndroid Build Coastguard Worker addSingleMaskFormat(glyphsWithSameFormat, format);
1323*c8dee2aaSAndroid Build Coastguard Worker format = nextFormat;
1324*c8dee2aaSAndroid Build Coastguard Worker startIndex = i;
1325*c8dee2aaSAndroid Build Coastguard Worker }
1326*c8dee2aaSAndroid Build Coastguard Worker }
1327*c8dee2aaSAndroid Build Coastguard Worker auto interval = accepted.last(accepted.size() - startIndex);
1328*c8dee2aaSAndroid Build Coastguard Worker auto glyphsWithSameFormat = SkMakeZip(interval.get<0>(), interval.get<1>());
1329*c8dee2aaSAndroid Build Coastguard Worker addSingleMaskFormat(glyphsWithSameFormat, format);
1330*c8dee2aaSAndroid Build Coastguard Worker }
1331*c8dee2aaSAndroid Build Coastguard Worker } // namespace
1332*c8dee2aaSAndroid Build Coastguard Worker
1333*c8dee2aaSAndroid Build Coastguard Worker namespace sktext::gpu {
1334*c8dee2aaSAndroid Build Coastguard Worker SubRun::~SubRun() = default;
flatten(SkWriteBuffer & buffer) const1335*c8dee2aaSAndroid Build Coastguard Worker void SubRun::flatten(SkWriteBuffer& buffer) const {
1336*c8dee2aaSAndroid Build Coastguard Worker buffer.writeInt(this->subRunStreamTag());
1337*c8dee2aaSAndroid Build Coastguard Worker this->doFlatten(buffer);
1338*c8dee2aaSAndroid Build Coastguard Worker }
1339*c8dee2aaSAndroid Build Coastguard Worker
MakeFromBuffer(SkReadBuffer & buffer,SubRunAllocator * alloc,const SkStrikeClient * client)1340*c8dee2aaSAndroid Build Coastguard Worker SubRunOwner SubRun::MakeFromBuffer(SkReadBuffer& buffer,
1341*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc,
1342*c8dee2aaSAndroid Build Coastguard Worker const SkStrikeClient* client) {
1343*c8dee2aaSAndroid Build Coastguard Worker using Maker = SubRunOwner (*)(SkReadBuffer&,
1344*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator*,
1345*c8dee2aaSAndroid Build Coastguard Worker const SkStrikeClient*);
1346*c8dee2aaSAndroid Build Coastguard Worker
1347*c8dee2aaSAndroid Build Coastguard Worker static Maker makers[kSubRunStreamTagCount] = {
1348*c8dee2aaSAndroid Build Coastguard Worker nullptr, // 0 index is bad.
1349*c8dee2aaSAndroid Build Coastguard Worker DirectMaskSubRun::MakeFromBuffer,
1350*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_DISABLE_SDF_TEXT)
1351*c8dee2aaSAndroid Build Coastguard Worker SDFTSubRun::MakeFromBuffer,
1352*c8dee2aaSAndroid Build Coastguard Worker #endif
1353*c8dee2aaSAndroid Build Coastguard Worker TransformedMaskSubRun::MakeFromBuffer,
1354*c8dee2aaSAndroid Build Coastguard Worker PathSubRun::MakeFromBuffer,
1355*c8dee2aaSAndroid Build Coastguard Worker DrawableSubRun::MakeFromBuffer,
1356*c8dee2aaSAndroid Build Coastguard Worker };
1357*c8dee2aaSAndroid Build Coastguard Worker int subRunTypeInt = buffer.readInt();
1358*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(kBad < subRunTypeInt && subRunTypeInt < kSubRunStreamTagCount)) {
1359*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
1360*c8dee2aaSAndroid Build Coastguard Worker }
1361*c8dee2aaSAndroid Build Coastguard Worker auto maker = makers[subRunTypeInt];
1362*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(maker != nullptr)) { return nullptr; }
1363*c8dee2aaSAndroid Build Coastguard Worker return maker(buffer, alloc, client);
1364*c8dee2aaSAndroid Build Coastguard Worker }
1365*c8dee2aaSAndroid Build Coastguard Worker
1366*c8dee2aaSAndroid Build Coastguard Worker // -- SubRunContainer ------------------------------------------------------------------------------
SubRunContainer(const SkMatrix & initialPositionMatrix)1367*c8dee2aaSAndroid Build Coastguard Worker SubRunContainer::SubRunContainer(const SkMatrix& initialPositionMatrix)
1368*c8dee2aaSAndroid Build Coastguard Worker : fInitialPositionMatrix{initialPositionMatrix} {}
1369*c8dee2aaSAndroid Build Coastguard Worker
flattenAllocSizeHint(SkWriteBuffer & buffer) const1370*c8dee2aaSAndroid Build Coastguard Worker void SubRunContainer::flattenAllocSizeHint(SkWriteBuffer& buffer) const {
1371*c8dee2aaSAndroid Build Coastguard Worker int unflattenSizeHint = 0;
1372*c8dee2aaSAndroid Build Coastguard Worker for (auto& subrun : fSubRuns) {
1373*c8dee2aaSAndroid Build Coastguard Worker unflattenSizeHint += subrun.unflattenSize();
1374*c8dee2aaSAndroid Build Coastguard Worker }
1375*c8dee2aaSAndroid Build Coastguard Worker buffer.writeInt(unflattenSizeHint);
1376*c8dee2aaSAndroid Build Coastguard Worker }
1377*c8dee2aaSAndroid Build Coastguard Worker
AllocSizeHintFromBuffer(SkReadBuffer & buffer)1378*c8dee2aaSAndroid Build Coastguard Worker int SubRunContainer::AllocSizeHintFromBuffer(SkReadBuffer& buffer) {
1379*c8dee2aaSAndroid Build Coastguard Worker int subRunsSizeHint = buffer.readInt();
1380*c8dee2aaSAndroid Build Coastguard Worker
1381*c8dee2aaSAndroid Build Coastguard Worker // Since the hint doesn't affect correctness, if it looks fishy just pick a reasonable
1382*c8dee2aaSAndroid Build Coastguard Worker // value.
1383*c8dee2aaSAndroid Build Coastguard Worker if (subRunsSizeHint < 0 || (1 << 16) < subRunsSizeHint) {
1384*c8dee2aaSAndroid Build Coastguard Worker subRunsSizeHint = 128;
1385*c8dee2aaSAndroid Build Coastguard Worker }
1386*c8dee2aaSAndroid Build Coastguard Worker return subRunsSizeHint;
1387*c8dee2aaSAndroid Build Coastguard Worker }
1388*c8dee2aaSAndroid Build Coastguard Worker
flattenRuns(SkWriteBuffer & buffer) const1389*c8dee2aaSAndroid Build Coastguard Worker void SubRunContainer::flattenRuns(SkWriteBuffer& buffer) const {
1390*c8dee2aaSAndroid Build Coastguard Worker buffer.writeMatrix(fInitialPositionMatrix);
1391*c8dee2aaSAndroid Build Coastguard Worker int subRunCount = 0;
1392*c8dee2aaSAndroid Build Coastguard Worker for ([[maybe_unused]] auto& subRun : fSubRuns) {
1393*c8dee2aaSAndroid Build Coastguard Worker subRunCount += 1;
1394*c8dee2aaSAndroid Build Coastguard Worker }
1395*c8dee2aaSAndroid Build Coastguard Worker buffer.writeInt(subRunCount);
1396*c8dee2aaSAndroid Build Coastguard Worker for (auto& subRun : fSubRuns) {
1397*c8dee2aaSAndroid Build Coastguard Worker subRun.flatten(buffer);
1398*c8dee2aaSAndroid Build Coastguard Worker }
1399*c8dee2aaSAndroid Build Coastguard Worker }
1400*c8dee2aaSAndroid Build Coastguard Worker
MakeFromBufferInAlloc(SkReadBuffer & buffer,const SkStrikeClient * client,SubRunAllocator * alloc)1401*c8dee2aaSAndroid Build Coastguard Worker SubRunContainerOwner SubRunContainer::MakeFromBufferInAlloc(SkReadBuffer& buffer,
1402*c8dee2aaSAndroid Build Coastguard Worker const SkStrikeClient* client,
1403*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc) {
1404*c8dee2aaSAndroid Build Coastguard Worker SkMatrix positionMatrix;
1405*c8dee2aaSAndroid Build Coastguard Worker buffer.readMatrix(&positionMatrix);
1406*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.isValid()) { return nullptr; }
1407*c8dee2aaSAndroid Build Coastguard Worker SubRunContainerOwner container = alloc->makeUnique<SubRunContainer>(positionMatrix);
1408*c8dee2aaSAndroid Build Coastguard Worker
1409*c8dee2aaSAndroid Build Coastguard Worker int subRunCount = buffer.readInt();
1410*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(subRunCount > 0)) { return nullptr; }
1411*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < subRunCount; ++i) {
1412*c8dee2aaSAndroid Build Coastguard Worker auto subRunOwner = SubRun::MakeFromBuffer(buffer, alloc, client);
1413*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(subRunOwner != nullptr)) { return nullptr; }
1414*c8dee2aaSAndroid Build Coastguard Worker if (subRunOwner != nullptr) {
1415*c8dee2aaSAndroid Build Coastguard Worker container->fSubRuns.append(std::move(subRunOwner));
1416*c8dee2aaSAndroid Build Coastguard Worker }
1417*c8dee2aaSAndroid Build Coastguard Worker }
1418*c8dee2aaSAndroid Build Coastguard Worker return container;
1419*c8dee2aaSAndroid Build Coastguard Worker }
1420*c8dee2aaSAndroid Build Coastguard Worker
EstimateAllocSize(const GlyphRunList & glyphRunList)1421*c8dee2aaSAndroid Build Coastguard Worker size_t SubRunContainer::EstimateAllocSize(const GlyphRunList& glyphRunList) {
1422*c8dee2aaSAndroid Build Coastguard Worker // The difference in alignment from the per-glyph data to the SubRun;
1423*c8dee2aaSAndroid Build Coastguard Worker constexpr size_t alignDiff = alignof(DirectMaskSubRun) - alignof(SkPoint);
1424*c8dee2aaSAndroid Build Coastguard Worker constexpr size_t vertexDataToSubRunPadding = alignDiff > 0 ? alignDiff : 0;
1425*c8dee2aaSAndroid Build Coastguard Worker size_t totalGlyphCount = glyphRunList.totalGlyphCount();
1426*c8dee2aaSAndroid Build Coastguard Worker // This is optimized for DirectMaskSubRun which is by far the most common case.
1427*c8dee2aaSAndroid Build Coastguard Worker return totalGlyphCount * sizeof(SkPoint)
1428*c8dee2aaSAndroid Build Coastguard Worker + GlyphVector::GlyphVectorSize(totalGlyphCount)
1429*c8dee2aaSAndroid Build Coastguard Worker + glyphRunList.runCount() * (sizeof(DirectMaskSubRun) + vertexDataToSubRunPadding)
1430*c8dee2aaSAndroid Build Coastguard Worker + sizeof(SubRunContainer);
1431*c8dee2aaSAndroid Build Coastguard Worker }
1432*c8dee2aaSAndroid Build Coastguard Worker
find_maximum_glyph_dimension(StrikeForGPU * strike,SkSpan<const SkGlyphID> glyphs)1433*c8dee2aaSAndroid Build Coastguard Worker SkScalar find_maximum_glyph_dimension(StrikeForGPU* strike, SkSpan<const SkGlyphID> glyphs) {
1434*c8dee2aaSAndroid Build Coastguard Worker StrikeMutationMonitor m{strike};
1435*c8dee2aaSAndroid Build Coastguard Worker SkScalar maxDimension = 0;
1436*c8dee2aaSAndroid Build Coastguard Worker for (SkGlyphID glyphID : glyphs) {
1437*c8dee2aaSAndroid Build Coastguard Worker SkGlyphDigest digest = strike->digestFor(kMask, SkPackedGlyphID{glyphID});
1438*c8dee2aaSAndroid Build Coastguard Worker maxDimension = std::max(static_cast<SkScalar>(digest.maxDimension()), maxDimension);
1439*c8dee2aaSAndroid Build Coastguard Worker }
1440*c8dee2aaSAndroid Build Coastguard Worker
1441*c8dee2aaSAndroid Build Coastguard Worker return maxDimension;
1442*c8dee2aaSAndroid Build Coastguard Worker }
1443*c8dee2aaSAndroid Build Coastguard Worker
1444*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_DISABLE_SDF_TEXT)
1445*c8dee2aaSAndroid Build Coastguard Worker std::tuple<SkZip<const SkPackedGlyphID, const SkPoint>, SkZip<SkGlyphID, SkPoint>, SkRect>
prepare_for_SDFT_drawing(StrikeForGPU * strike,const SkMatrix & creationMatrix,SkZip<const SkGlyphID,const SkPoint> source,SkZip<SkPackedGlyphID,SkPoint> acceptedBuffer,SkZip<SkGlyphID,SkPoint> rejectedBuffer)1446*c8dee2aaSAndroid Build Coastguard Worker prepare_for_SDFT_drawing(StrikeForGPU* strike,
1447*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& creationMatrix,
1448*c8dee2aaSAndroid Build Coastguard Worker SkZip<const SkGlyphID, const SkPoint> source,
1449*c8dee2aaSAndroid Build Coastguard Worker SkZip<SkPackedGlyphID, SkPoint> acceptedBuffer,
1450*c8dee2aaSAndroid Build Coastguard Worker SkZip<SkGlyphID, SkPoint> rejectedBuffer) {
1451*c8dee2aaSAndroid Build Coastguard Worker int acceptedSize = 0,
1452*c8dee2aaSAndroid Build Coastguard Worker rejectedSize = 0;
1453*c8dee2aaSAndroid Build Coastguard Worker SkGlyphRect boundingRect = skglyph::empty_rect();
1454*c8dee2aaSAndroid Build Coastguard Worker StrikeMutationMonitor m{strike};
1455*c8dee2aaSAndroid Build Coastguard Worker for (const auto [glyphID, pos] : source) {
1456*c8dee2aaSAndroid Build Coastguard Worker if (!SkIsFinite(pos.x(), pos.y())) {
1457*c8dee2aaSAndroid Build Coastguard Worker continue;
1458*c8dee2aaSAndroid Build Coastguard Worker }
1459*c8dee2aaSAndroid Build Coastguard Worker
1460*c8dee2aaSAndroid Build Coastguard Worker const SkPackedGlyphID packedID{glyphID};
1461*c8dee2aaSAndroid Build Coastguard Worker switch (const SkGlyphDigest digest = strike->digestFor(skglyph::kSDFT, packedID);
1462*c8dee2aaSAndroid Build Coastguard Worker digest.actionFor(skglyph::kSDFT)) {
1463*c8dee2aaSAndroid Build Coastguard Worker case GlyphAction::kAccept: {
1464*c8dee2aaSAndroid Build Coastguard Worker SkPoint mappedPos = creationMatrix.mapPoint(pos);
1465*c8dee2aaSAndroid Build Coastguard Worker const SkGlyphRect glyphBounds =
1466*c8dee2aaSAndroid Build Coastguard Worker digest.bounds()
1467*c8dee2aaSAndroid Build Coastguard Worker // The SDFT glyphs have 2-pixel wide padding that should
1468*c8dee2aaSAndroid Build Coastguard Worker // not be used in calculating the source rectangle.
1469*c8dee2aaSAndroid Build Coastguard Worker .inset(SK_DistanceFieldInset, SK_DistanceFieldInset)
1470*c8dee2aaSAndroid Build Coastguard Worker .offset(mappedPos);
1471*c8dee2aaSAndroid Build Coastguard Worker boundingRect = skglyph::rect_union(boundingRect, glyphBounds);
1472*c8dee2aaSAndroid Build Coastguard Worker acceptedBuffer[acceptedSize++] = std::make_tuple(packedID, glyphBounds.leftTop());
1473*c8dee2aaSAndroid Build Coastguard Worker break;
1474*c8dee2aaSAndroid Build Coastguard Worker }
1475*c8dee2aaSAndroid Build Coastguard Worker case GlyphAction::kReject:
1476*c8dee2aaSAndroid Build Coastguard Worker rejectedBuffer[rejectedSize++] = std::make_tuple(glyphID, pos);
1477*c8dee2aaSAndroid Build Coastguard Worker break;
1478*c8dee2aaSAndroid Build Coastguard Worker default:
1479*c8dee2aaSAndroid Build Coastguard Worker break;
1480*c8dee2aaSAndroid Build Coastguard Worker }
1481*c8dee2aaSAndroid Build Coastguard Worker }
1482*c8dee2aaSAndroid Build Coastguard Worker
1483*c8dee2aaSAndroid Build Coastguard Worker return {acceptedBuffer.first(acceptedSize),
1484*c8dee2aaSAndroid Build Coastguard Worker rejectedBuffer.first(rejectedSize),
1485*c8dee2aaSAndroid Build Coastguard Worker boundingRect.rect()};
1486*c8dee2aaSAndroid Build Coastguard Worker }
1487*c8dee2aaSAndroid Build Coastguard Worker #endif
1488*c8dee2aaSAndroid Build Coastguard Worker
1489*c8dee2aaSAndroid Build Coastguard Worker std::tuple<SkZip<const SkPackedGlyphID, const SkPoint, const SkMask::Format>,
1490*c8dee2aaSAndroid Build Coastguard Worker SkZip<SkGlyphID, SkPoint>,
1491*c8dee2aaSAndroid Build Coastguard Worker SkRect>
prepare_for_direct_mask_drawing(StrikeForGPU * strike,const SkMatrix & positionMatrix,SkZip<const SkGlyphID,const SkPoint> source,SkZip<SkPackedGlyphID,SkPoint,SkMask::Format> acceptedBuffer,SkZip<SkGlyphID,SkPoint> rejectedBuffer)1492*c8dee2aaSAndroid Build Coastguard Worker prepare_for_direct_mask_drawing(StrikeForGPU* strike,
1493*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& positionMatrix,
1494*c8dee2aaSAndroid Build Coastguard Worker SkZip<const SkGlyphID, const SkPoint> source,
1495*c8dee2aaSAndroid Build Coastguard Worker SkZip<SkPackedGlyphID, SkPoint, SkMask::Format> acceptedBuffer,
1496*c8dee2aaSAndroid Build Coastguard Worker SkZip<SkGlyphID, SkPoint> rejectedBuffer) {
1497*c8dee2aaSAndroid Build Coastguard Worker const SkIPoint mask = strike->roundingSpec().ignorePositionFieldMask;
1498*c8dee2aaSAndroid Build Coastguard Worker const SkPoint halfSampleFreq = strike->roundingSpec().halfAxisSampleFreq;
1499*c8dee2aaSAndroid Build Coastguard Worker
1500*c8dee2aaSAndroid Build Coastguard Worker // Build up the mapping from source space to device space. Add the rounding constant
1501*c8dee2aaSAndroid Build Coastguard Worker // halfSampleFreq, so we just need to floor to get the device result.
1502*c8dee2aaSAndroid Build Coastguard Worker SkMatrix positionMatrixWithRounding = positionMatrix;
1503*c8dee2aaSAndroid Build Coastguard Worker positionMatrixWithRounding.postTranslate(halfSampleFreq.x(), halfSampleFreq.y());
1504*c8dee2aaSAndroid Build Coastguard Worker
1505*c8dee2aaSAndroid Build Coastguard Worker int acceptedSize = 0,
1506*c8dee2aaSAndroid Build Coastguard Worker rejectedSize = 0;
1507*c8dee2aaSAndroid Build Coastguard Worker SkGlyphRect boundingRect = skglyph::empty_rect();
1508*c8dee2aaSAndroid Build Coastguard Worker StrikeMutationMonitor m{strike};
1509*c8dee2aaSAndroid Build Coastguard Worker for (auto [glyphID, pos] : source) {
1510*c8dee2aaSAndroid Build Coastguard Worker if (!SkIsFinite(pos.x(), pos.y())) {
1511*c8dee2aaSAndroid Build Coastguard Worker continue;
1512*c8dee2aaSAndroid Build Coastguard Worker }
1513*c8dee2aaSAndroid Build Coastguard Worker
1514*c8dee2aaSAndroid Build Coastguard Worker const SkPoint mappedPos = positionMatrixWithRounding.mapPoint(pos);
1515*c8dee2aaSAndroid Build Coastguard Worker const SkPackedGlyphID packedID{glyphID, mappedPos, mask};
1516*c8dee2aaSAndroid Build Coastguard Worker switch (const SkGlyphDigest digest = strike->digestFor(skglyph::kDirectMask, packedID);
1517*c8dee2aaSAndroid Build Coastguard Worker digest.actionFor(skglyph::kDirectMask)) {
1518*c8dee2aaSAndroid Build Coastguard Worker case GlyphAction::kAccept: {
1519*c8dee2aaSAndroid Build Coastguard Worker const SkPoint roundedPos{SkScalarFloorToScalar(mappedPos.x()),
1520*c8dee2aaSAndroid Build Coastguard Worker SkScalarFloorToScalar(mappedPos.y())};
1521*c8dee2aaSAndroid Build Coastguard Worker const SkGlyphRect glyphBounds = digest.bounds().offset(roundedPos);
1522*c8dee2aaSAndroid Build Coastguard Worker boundingRect = skglyph::rect_union(boundingRect, glyphBounds);
1523*c8dee2aaSAndroid Build Coastguard Worker acceptedBuffer[acceptedSize++] =
1524*c8dee2aaSAndroid Build Coastguard Worker std::make_tuple(packedID, glyphBounds.leftTop(), digest.maskFormat());
1525*c8dee2aaSAndroid Build Coastguard Worker break;
1526*c8dee2aaSAndroid Build Coastguard Worker }
1527*c8dee2aaSAndroid Build Coastguard Worker case GlyphAction::kReject:
1528*c8dee2aaSAndroid Build Coastguard Worker rejectedBuffer[rejectedSize++] = std::make_tuple(glyphID, pos);
1529*c8dee2aaSAndroid Build Coastguard Worker break;
1530*c8dee2aaSAndroid Build Coastguard Worker default:
1531*c8dee2aaSAndroid Build Coastguard Worker break;
1532*c8dee2aaSAndroid Build Coastguard Worker }
1533*c8dee2aaSAndroid Build Coastguard Worker }
1534*c8dee2aaSAndroid Build Coastguard Worker
1535*c8dee2aaSAndroid Build Coastguard Worker return {acceptedBuffer.first(acceptedSize),
1536*c8dee2aaSAndroid Build Coastguard Worker rejectedBuffer.first(rejectedSize),
1537*c8dee2aaSAndroid Build Coastguard Worker boundingRect.rect()};
1538*c8dee2aaSAndroid Build Coastguard Worker }
1539*c8dee2aaSAndroid Build Coastguard Worker
1540*c8dee2aaSAndroid Build Coastguard Worker std::tuple<SkZip<const SkPackedGlyphID, const SkPoint, const SkMask::Format>,
1541*c8dee2aaSAndroid Build Coastguard Worker SkZip<SkGlyphID, SkPoint>,
1542*c8dee2aaSAndroid Build Coastguard Worker SkRect>
prepare_for_mask_drawing(StrikeForGPU * strike,const SkMatrix & creationMatrix,SkZip<const SkGlyphID,const SkPoint> source,SkZip<SkPackedGlyphID,SkPoint,SkMask::Format> acceptedBuffer,SkZip<SkGlyphID,SkPoint> rejectedBuffer)1543*c8dee2aaSAndroid Build Coastguard Worker prepare_for_mask_drawing(StrikeForGPU* strike,
1544*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& creationMatrix,
1545*c8dee2aaSAndroid Build Coastguard Worker SkZip<const SkGlyphID, const SkPoint> source,
1546*c8dee2aaSAndroid Build Coastguard Worker SkZip<SkPackedGlyphID, SkPoint, SkMask::Format> acceptedBuffer,
1547*c8dee2aaSAndroid Build Coastguard Worker SkZip<SkGlyphID, SkPoint> rejectedBuffer) {
1548*c8dee2aaSAndroid Build Coastguard Worker int acceptedSize = 0,
1549*c8dee2aaSAndroid Build Coastguard Worker rejectedSize = 0;
1550*c8dee2aaSAndroid Build Coastguard Worker SkGlyphRect boundingRect = skglyph::empty_rect();
1551*c8dee2aaSAndroid Build Coastguard Worker StrikeMutationMonitor m{strike};
1552*c8dee2aaSAndroid Build Coastguard Worker for (auto [glyphID, pos] : source) {
1553*c8dee2aaSAndroid Build Coastguard Worker if (!SkIsFinite(pos.x(), pos.y())) {
1554*c8dee2aaSAndroid Build Coastguard Worker continue;
1555*c8dee2aaSAndroid Build Coastguard Worker }
1556*c8dee2aaSAndroid Build Coastguard Worker
1557*c8dee2aaSAndroid Build Coastguard Worker const SkPackedGlyphID packedID{glyphID};
1558*c8dee2aaSAndroid Build Coastguard Worker switch (const SkGlyphDigest digest = strike->digestFor(kMask, packedID);
1559*c8dee2aaSAndroid Build Coastguard Worker digest.actionFor(kMask)) {
1560*c8dee2aaSAndroid Build Coastguard Worker case GlyphAction::kAccept: {
1561*c8dee2aaSAndroid Build Coastguard Worker const SkPoint mappedPos = creationMatrix.mapPoint(pos);
1562*c8dee2aaSAndroid Build Coastguard Worker const SkGlyphRect glyphBounds = digest.bounds().offset(mappedPos);
1563*c8dee2aaSAndroid Build Coastguard Worker boundingRect = skglyph::rect_union(boundingRect, glyphBounds);
1564*c8dee2aaSAndroid Build Coastguard Worker acceptedBuffer[acceptedSize++] =
1565*c8dee2aaSAndroid Build Coastguard Worker std::make_tuple(packedID, glyphBounds.leftTop(), digest.maskFormat());
1566*c8dee2aaSAndroid Build Coastguard Worker break;
1567*c8dee2aaSAndroid Build Coastguard Worker }
1568*c8dee2aaSAndroid Build Coastguard Worker case GlyphAction::kReject:
1569*c8dee2aaSAndroid Build Coastguard Worker rejectedBuffer[rejectedSize++] = std::make_tuple(glyphID, pos);
1570*c8dee2aaSAndroid Build Coastguard Worker break;
1571*c8dee2aaSAndroid Build Coastguard Worker default:
1572*c8dee2aaSAndroid Build Coastguard Worker break;
1573*c8dee2aaSAndroid Build Coastguard Worker }
1574*c8dee2aaSAndroid Build Coastguard Worker }
1575*c8dee2aaSAndroid Build Coastguard Worker
1576*c8dee2aaSAndroid Build Coastguard Worker return {acceptedBuffer.first(acceptedSize),
1577*c8dee2aaSAndroid Build Coastguard Worker rejectedBuffer.first(rejectedSize),
1578*c8dee2aaSAndroid Build Coastguard Worker boundingRect.rect()};
1579*c8dee2aaSAndroid Build Coastguard Worker }
1580*c8dee2aaSAndroid Build Coastguard Worker
1581*c8dee2aaSAndroid Build Coastguard Worker std::tuple<SkZip<const SkGlyphID, const SkPoint>, SkZip<SkGlyphID, SkPoint>>
prepare_for_path_drawing(StrikeForGPU * strike,SkZip<const SkGlyphID,const SkPoint> source,SkZip<SkGlyphID,SkPoint> acceptedBuffer,SkZip<SkGlyphID,SkPoint> rejectedBuffer)1582*c8dee2aaSAndroid Build Coastguard Worker prepare_for_path_drawing(StrikeForGPU* strike,
1583*c8dee2aaSAndroid Build Coastguard Worker SkZip<const SkGlyphID, const SkPoint> source,
1584*c8dee2aaSAndroid Build Coastguard Worker SkZip<SkGlyphID, SkPoint> acceptedBuffer,
1585*c8dee2aaSAndroid Build Coastguard Worker SkZip<SkGlyphID, SkPoint> rejectedBuffer) {
1586*c8dee2aaSAndroid Build Coastguard Worker int acceptedSize = 0;
1587*c8dee2aaSAndroid Build Coastguard Worker int rejectedSize = 0;
1588*c8dee2aaSAndroid Build Coastguard Worker StrikeMutationMonitor m{strike};
1589*c8dee2aaSAndroid Build Coastguard Worker for (const auto [glyphID, pos] : source) {
1590*c8dee2aaSAndroid Build Coastguard Worker if (!SkIsFinite(pos.x(), pos.y())) {
1591*c8dee2aaSAndroid Build Coastguard Worker continue;
1592*c8dee2aaSAndroid Build Coastguard Worker }
1593*c8dee2aaSAndroid Build Coastguard Worker
1594*c8dee2aaSAndroid Build Coastguard Worker switch (strike->digestFor(skglyph::kPath, SkPackedGlyphID{glyphID})
1595*c8dee2aaSAndroid Build Coastguard Worker .actionFor(skglyph::kPath)) {
1596*c8dee2aaSAndroid Build Coastguard Worker case GlyphAction::kAccept:
1597*c8dee2aaSAndroid Build Coastguard Worker acceptedBuffer[acceptedSize++] = std::make_tuple(glyphID, pos);
1598*c8dee2aaSAndroid Build Coastguard Worker break;
1599*c8dee2aaSAndroid Build Coastguard Worker case GlyphAction::kReject:
1600*c8dee2aaSAndroid Build Coastguard Worker rejectedBuffer[rejectedSize++] = std::make_tuple(glyphID, pos);
1601*c8dee2aaSAndroid Build Coastguard Worker break;
1602*c8dee2aaSAndroid Build Coastguard Worker default:
1603*c8dee2aaSAndroid Build Coastguard Worker break;
1604*c8dee2aaSAndroid Build Coastguard Worker }
1605*c8dee2aaSAndroid Build Coastguard Worker }
1606*c8dee2aaSAndroid Build Coastguard Worker return {acceptedBuffer.first(acceptedSize), rejectedBuffer.first(rejectedSize)};
1607*c8dee2aaSAndroid Build Coastguard Worker }
1608*c8dee2aaSAndroid Build Coastguard Worker
1609*c8dee2aaSAndroid Build Coastguard Worker std::tuple<SkZip<const SkGlyphID, const SkPoint>, SkZip<SkGlyphID, SkPoint>>
prepare_for_drawable_drawing(StrikeForGPU * strike,SkZip<const SkGlyphID,const SkPoint> source,SkZip<SkGlyphID,SkPoint> acceptedBuffer,SkZip<SkGlyphID,SkPoint> rejectedBuffer)1610*c8dee2aaSAndroid Build Coastguard Worker prepare_for_drawable_drawing(StrikeForGPU* strike,
1611*c8dee2aaSAndroid Build Coastguard Worker SkZip<const SkGlyphID, const SkPoint> source,
1612*c8dee2aaSAndroid Build Coastguard Worker SkZip<SkGlyphID, SkPoint> acceptedBuffer,
1613*c8dee2aaSAndroid Build Coastguard Worker SkZip<SkGlyphID, SkPoint> rejectedBuffer) {
1614*c8dee2aaSAndroid Build Coastguard Worker int acceptedSize = 0;
1615*c8dee2aaSAndroid Build Coastguard Worker int rejectedSize = 0;
1616*c8dee2aaSAndroid Build Coastguard Worker StrikeMutationMonitor m{strike};
1617*c8dee2aaSAndroid Build Coastguard Worker for (const auto [glyphID, pos] : source) {
1618*c8dee2aaSAndroid Build Coastguard Worker if (!SkIsFinite(pos.x(), pos.y())) {
1619*c8dee2aaSAndroid Build Coastguard Worker continue;
1620*c8dee2aaSAndroid Build Coastguard Worker }
1621*c8dee2aaSAndroid Build Coastguard Worker
1622*c8dee2aaSAndroid Build Coastguard Worker switch (strike->digestFor(skglyph::kDrawable, SkPackedGlyphID{glyphID})
1623*c8dee2aaSAndroid Build Coastguard Worker .actionFor(skglyph::kDrawable)) {
1624*c8dee2aaSAndroid Build Coastguard Worker case GlyphAction::kAccept:
1625*c8dee2aaSAndroid Build Coastguard Worker acceptedBuffer[acceptedSize++] = std::make_tuple(glyphID, pos);
1626*c8dee2aaSAndroid Build Coastguard Worker break;
1627*c8dee2aaSAndroid Build Coastguard Worker case GlyphAction::kReject:
1628*c8dee2aaSAndroid Build Coastguard Worker rejectedBuffer[rejectedSize++] = std::make_tuple(glyphID, pos);
1629*c8dee2aaSAndroid Build Coastguard Worker break;
1630*c8dee2aaSAndroid Build Coastguard Worker default:
1631*c8dee2aaSAndroid Build Coastguard Worker break;
1632*c8dee2aaSAndroid Build Coastguard Worker }
1633*c8dee2aaSAndroid Build Coastguard Worker }
1634*c8dee2aaSAndroid Build Coastguard Worker return {acceptedBuffer.first(acceptedSize), rejectedBuffer.first(rejectedSize)};
1635*c8dee2aaSAndroid Build Coastguard Worker }
1636*c8dee2aaSAndroid Build Coastguard Worker
1637*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_DISABLE_SDF_TEXT)
1638*c8dee2aaSAndroid Build Coastguard Worker static std::tuple<SkStrikeSpec, SkScalar, sktext::gpu::SDFTMatrixRange>
make_sdft_strike_spec(const SkFont & font,const SkPaint & paint,const SkSurfaceProps & surfaceProps,const SkMatrix & deviceMatrix,const SkPoint & textLocation,const sktext::gpu::SubRunControl & control)1639*c8dee2aaSAndroid Build Coastguard Worker make_sdft_strike_spec(const SkFont& font, const SkPaint& paint,
1640*c8dee2aaSAndroid Build Coastguard Worker const SkSurfaceProps& surfaceProps, const SkMatrix& deviceMatrix,
1641*c8dee2aaSAndroid Build Coastguard Worker const SkPoint& textLocation, const sktext::gpu::SubRunControl& control) {
1642*c8dee2aaSAndroid Build Coastguard Worker // Add filter to the paint which creates the SDFT data for A8 masks.
1643*c8dee2aaSAndroid Build Coastguard Worker SkPaint dfPaint{paint};
1644*c8dee2aaSAndroid Build Coastguard Worker dfPaint.setMaskFilter(sktext::gpu::SDFMaskFilter::Make());
1645*c8dee2aaSAndroid Build Coastguard Worker
1646*c8dee2aaSAndroid Build Coastguard Worker auto [dfFont, strikeToSourceScale, matrixRange] = control.getSDFFont(font, deviceMatrix,
1647*c8dee2aaSAndroid Build Coastguard Worker textLocation);
1648*c8dee2aaSAndroid Build Coastguard Worker
1649*c8dee2aaSAndroid Build Coastguard Worker // Adjust the stroke width by the scale factor for drawing the SDFT.
1650*c8dee2aaSAndroid Build Coastguard Worker dfPaint.setStrokeWidth(paint.getStrokeWidth() / strikeToSourceScale);
1651*c8dee2aaSAndroid Build Coastguard Worker
1652*c8dee2aaSAndroid Build Coastguard Worker // Check for dashing and adjust the intervals.
1653*c8dee2aaSAndroid Build Coastguard Worker if (SkPathEffect* pathEffect = paint.getPathEffect(); pathEffect != nullptr) {
1654*c8dee2aaSAndroid Build Coastguard Worker SkPathEffectBase::DashInfo dashInfo;
1655*c8dee2aaSAndroid Build Coastguard Worker if (as_PEB(pathEffect)->asADash(&dashInfo) == SkPathEffectBase::DashType::kDash) {
1656*c8dee2aaSAndroid Build Coastguard Worker if (dashInfo.fCount > 0) {
1657*c8dee2aaSAndroid Build Coastguard Worker // Allocate the intervals.
1658*c8dee2aaSAndroid Build Coastguard Worker std::vector<SkScalar> scaledIntervals(dashInfo.fCount);
1659*c8dee2aaSAndroid Build Coastguard Worker dashInfo.fIntervals = scaledIntervals.data();
1660*c8dee2aaSAndroid Build Coastguard Worker // Call again to get the interval data.
1661*c8dee2aaSAndroid Build Coastguard Worker (void)as_PEB(pathEffect)->asADash(&dashInfo);
1662*c8dee2aaSAndroid Build Coastguard Worker for (SkScalar& interval : scaledIntervals) {
1663*c8dee2aaSAndroid Build Coastguard Worker interval /= strikeToSourceScale;
1664*c8dee2aaSAndroid Build Coastguard Worker }
1665*c8dee2aaSAndroid Build Coastguard Worker auto scaledDashes = SkDashPathEffect::Make(scaledIntervals.data(),
1666*c8dee2aaSAndroid Build Coastguard Worker scaledIntervals.size(),
1667*c8dee2aaSAndroid Build Coastguard Worker dashInfo.fPhase / strikeToSourceScale);
1668*c8dee2aaSAndroid Build Coastguard Worker dfPaint.setPathEffect(scaledDashes);
1669*c8dee2aaSAndroid Build Coastguard Worker }
1670*c8dee2aaSAndroid Build Coastguard Worker }
1671*c8dee2aaSAndroid Build Coastguard Worker }
1672*c8dee2aaSAndroid Build Coastguard Worker
1673*c8dee2aaSAndroid Build Coastguard Worker // Fake-gamma and subpixel antialiasing are applied in the shader, so we ignore the
1674*c8dee2aaSAndroid Build Coastguard Worker // passed-in scaler context flags. (It's only used when we fall-back to bitmap text).
1675*c8dee2aaSAndroid Build Coastguard Worker SkScalerContextFlags flags = SkScalerContextFlags::kNone;
1676*c8dee2aaSAndroid Build Coastguard Worker SkStrikeSpec strikeSpec = SkStrikeSpec::MakeMask(dfFont, dfPaint, surfaceProps, flags,
1677*c8dee2aaSAndroid Build Coastguard Worker SkMatrix::I());
1678*c8dee2aaSAndroid Build Coastguard Worker
1679*c8dee2aaSAndroid Build Coastguard Worker return std::make_tuple(std::move(strikeSpec), strikeToSourceScale, matrixRange);
1680*c8dee2aaSAndroid Build Coastguard Worker }
1681*c8dee2aaSAndroid Build Coastguard Worker #endif
1682*c8dee2aaSAndroid Build Coastguard Worker
MakeInAlloc(const GlyphRunList & glyphRunList,const SkMatrix & positionMatrix,const SkPaint & runPaint,SkStrikeDeviceInfo strikeDeviceInfo,StrikeForGPUCacheInterface * strikeCache,SubRunAllocator * alloc,SubRunCreationBehavior creationBehavior,const char * tag)1683*c8dee2aaSAndroid Build Coastguard Worker SubRunContainerOwner SubRunContainer::MakeInAlloc(
1684*c8dee2aaSAndroid Build Coastguard Worker const GlyphRunList& glyphRunList,
1685*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& positionMatrix,
1686*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& runPaint,
1687*c8dee2aaSAndroid Build Coastguard Worker SkStrikeDeviceInfo strikeDeviceInfo,
1688*c8dee2aaSAndroid Build Coastguard Worker StrikeForGPUCacheInterface* strikeCache,
1689*c8dee2aaSAndroid Build Coastguard Worker SubRunAllocator* alloc,
1690*c8dee2aaSAndroid Build Coastguard Worker SubRunCreationBehavior creationBehavior,
1691*c8dee2aaSAndroid Build Coastguard Worker const char* tag) {
1692*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(alloc != nullptr);
1693*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(strikeDeviceInfo.fSubRunControl != nullptr);
1694*c8dee2aaSAndroid Build Coastguard Worker
1695*c8dee2aaSAndroid Build Coastguard Worker SubRunContainerOwner container = alloc->makeUnique<SubRunContainer>(positionMatrix);
1696*c8dee2aaSAndroid Build Coastguard Worker // If there is no SubRunControl description ignore all SubRuns.
1697*c8dee2aaSAndroid Build Coastguard Worker if (strikeDeviceInfo.fSubRunControl == nullptr) {
1698*c8dee2aaSAndroid Build Coastguard Worker return container;
1699*c8dee2aaSAndroid Build Coastguard Worker }
1700*c8dee2aaSAndroid Build Coastguard Worker
1701*c8dee2aaSAndroid Build Coastguard Worker const SkSurfaceProps deviceProps = strikeDeviceInfo.fSurfaceProps;
1702*c8dee2aaSAndroid Build Coastguard Worker const SkScalerContextFlags scalerContextFlags = strikeDeviceInfo.fScalerContextFlags;
1703*c8dee2aaSAndroid Build Coastguard Worker const SubRunControl* subRunControl = strikeDeviceInfo.fSubRunControl;
1704*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_DISABLE_SDF_TEXT)
1705*c8dee2aaSAndroid Build Coastguard Worker const SkScalar maxMaskSize = subRunControl->maxSize();
1706*c8dee2aaSAndroid Build Coastguard Worker #else
1707*c8dee2aaSAndroid Build Coastguard Worker const SkScalar maxMaskSize = 256;
1708*c8dee2aaSAndroid Build Coastguard Worker #endif
1709*c8dee2aaSAndroid Build Coastguard Worker
1710*c8dee2aaSAndroid Build Coastguard Worker // TODO: hoist the buffer structure to the GlyphRunBuilder. The buffer structure here is
1711*c8dee2aaSAndroid Build Coastguard Worker // still begin tuned, and this is expected to be slower until tuned.
1712*c8dee2aaSAndroid Build Coastguard Worker const int maxGlyphRunSize = glyphRunList.maxGlyphRunSize();
1713*c8dee2aaSAndroid Build Coastguard Worker
1714*c8dee2aaSAndroid Build Coastguard Worker // Accepted buffers.
1715*c8dee2aaSAndroid Build Coastguard Worker STArray<64, SkPackedGlyphID> acceptedPackedGlyphIDs;
1716*c8dee2aaSAndroid Build Coastguard Worker STArray<64, SkGlyphID> acceptedGlyphIDs;
1717*c8dee2aaSAndroid Build Coastguard Worker STArray<64, SkPoint> acceptedPositions;
1718*c8dee2aaSAndroid Build Coastguard Worker STArray<64, SkMask::Format> acceptedFormats;
1719*c8dee2aaSAndroid Build Coastguard Worker acceptedPackedGlyphIDs.resize(maxGlyphRunSize);
1720*c8dee2aaSAndroid Build Coastguard Worker acceptedGlyphIDs.resize(maxGlyphRunSize);
1721*c8dee2aaSAndroid Build Coastguard Worker acceptedPositions.resize(maxGlyphRunSize);
1722*c8dee2aaSAndroid Build Coastguard Worker acceptedFormats.resize(maxGlyphRunSize);
1723*c8dee2aaSAndroid Build Coastguard Worker
1724*c8dee2aaSAndroid Build Coastguard Worker // Rejected buffers.
1725*c8dee2aaSAndroid Build Coastguard Worker STArray<64, SkGlyphID> rejectedGlyphIDs;
1726*c8dee2aaSAndroid Build Coastguard Worker STArray<64, SkPoint> rejectedPositions;
1727*c8dee2aaSAndroid Build Coastguard Worker rejectedGlyphIDs.resize(maxGlyphRunSize);
1728*c8dee2aaSAndroid Build Coastguard Worker rejectedPositions.resize(maxGlyphRunSize);
1729*c8dee2aaSAndroid Build Coastguard Worker const auto rejectedBuffer = SkMakeZip(rejectedGlyphIDs, rejectedPositions);
1730*c8dee2aaSAndroid Build Coastguard Worker
1731*c8dee2aaSAndroid Build Coastguard Worker const SkPoint glyphRunListLocation = glyphRunList.sourceBounds().center();
1732*c8dee2aaSAndroid Build Coastguard Worker
1733*c8dee2aaSAndroid Build Coastguard Worker // Handle all the runs in the glyphRunList
1734*c8dee2aaSAndroid Build Coastguard Worker for (auto& glyphRun : glyphRunList) {
1735*c8dee2aaSAndroid Build Coastguard Worker SkZip<const SkGlyphID, const SkPoint> source = glyphRun.source();
1736*c8dee2aaSAndroid Build Coastguard Worker const SkFont& runFont = glyphRun.font();
1737*c8dee2aaSAndroid Build Coastguard Worker
1738*c8dee2aaSAndroid Build Coastguard Worker const SkScalar approximateDeviceTextSize =
1739*c8dee2aaSAndroid Build Coastguard Worker // Since the positionMatrix has the origin prepended, use the plain
1740*c8dee2aaSAndroid Build Coastguard Worker // sourceBounds from above.
1741*c8dee2aaSAndroid Build Coastguard Worker SkFontPriv::ApproximateTransformedTextSize(runFont, positionMatrix,
1742*c8dee2aaSAndroid Build Coastguard Worker glyphRunListLocation);
1743*c8dee2aaSAndroid Build Coastguard Worker
1744*c8dee2aaSAndroid Build Coastguard Worker // Atlas mask cases - SDFT and direct mask
1745*c8dee2aaSAndroid Build Coastguard Worker // Only consider using direct or SDFT drawing if not drawing hairlines and not too big.
1746*c8dee2aaSAndroid Build Coastguard Worker if ((runPaint.getStyle() != SkPaint::kStroke_Style || runPaint.getStrokeWidth() != 0) &&
1747*c8dee2aaSAndroid Build Coastguard Worker approximateDeviceTextSize < maxMaskSize) {
1748*c8dee2aaSAndroid Build Coastguard Worker
1749*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_DISABLE_SDF_TEXT)
1750*c8dee2aaSAndroid Build Coastguard Worker // SDFT case
1751*c8dee2aaSAndroid Build Coastguard Worker if (subRunControl->isSDFT(approximateDeviceTextSize, runPaint, positionMatrix)) {
1752*c8dee2aaSAndroid Build Coastguard Worker // Process SDFT - This should be the .009% case.
1753*c8dee2aaSAndroid Build Coastguard Worker const auto& [strikeSpec, strikeToSourceScale, matrixRange] =
1754*c8dee2aaSAndroid Build Coastguard Worker make_sdft_strike_spec(
1755*c8dee2aaSAndroid Build Coastguard Worker runFont, runPaint, deviceProps, positionMatrix,
1756*c8dee2aaSAndroid Build Coastguard Worker glyphRunListLocation, *subRunControl);
1757*c8dee2aaSAndroid Build Coastguard Worker
1758*c8dee2aaSAndroid Build Coastguard Worker if (!SkScalarNearlyZero(strikeToSourceScale)) {
1759*c8dee2aaSAndroid Build Coastguard Worker sk_sp<StrikeForGPU> strike = strikeSpec.findOrCreateScopedStrike(strikeCache);
1760*c8dee2aaSAndroid Build Coastguard Worker
1761*c8dee2aaSAndroid Build Coastguard Worker // The creationMatrix needs to scale the strike data when inverted and
1762*c8dee2aaSAndroid Build Coastguard Worker // multiplied by the positionMatrix. The final CTM should be:
1763*c8dee2aaSAndroid Build Coastguard Worker // [positionMatrix][scale by strikeToSourceScale],
1764*c8dee2aaSAndroid Build Coastguard Worker // which should equal the following because of the transform during the vertex
1765*c8dee2aaSAndroid Build Coastguard Worker // calculation,
1766*c8dee2aaSAndroid Build Coastguard Worker // [positionMatrix][creationMatrix]^-1.
1767*c8dee2aaSAndroid Build Coastguard Worker // So, the creation matrix needs to be
1768*c8dee2aaSAndroid Build Coastguard Worker // [scale by 1/strikeToSourceScale].
1769*c8dee2aaSAndroid Build Coastguard Worker SkMatrix creationMatrix =
1770*c8dee2aaSAndroid Build Coastguard Worker SkMatrix::Scale(1.f/strikeToSourceScale, 1.f/strikeToSourceScale);
1771*c8dee2aaSAndroid Build Coastguard Worker
1772*c8dee2aaSAndroid Build Coastguard Worker auto acceptedBuffer = SkMakeZip(acceptedPackedGlyphIDs, acceptedPositions);
1773*c8dee2aaSAndroid Build Coastguard Worker auto [accepted, rejected, creationBounds] = prepare_for_SDFT_drawing(
1774*c8dee2aaSAndroid Build Coastguard Worker strike.get(), creationMatrix, source, acceptedBuffer, rejectedBuffer);
1775*c8dee2aaSAndroid Build Coastguard Worker source = rejected;
1776*c8dee2aaSAndroid Build Coastguard Worker
1777*c8dee2aaSAndroid Build Coastguard Worker if (creationBehavior == kAddSubRuns && !accepted.empty()) {
1778*c8dee2aaSAndroid Build Coastguard Worker container->fSubRuns.append(SDFTSubRun::Make(
1779*c8dee2aaSAndroid Build Coastguard Worker accepted,
1780*c8dee2aaSAndroid Build Coastguard Worker runFont,
1781*c8dee2aaSAndroid Build Coastguard Worker strike->strikePromise(),
1782*c8dee2aaSAndroid Build Coastguard Worker creationMatrix,
1783*c8dee2aaSAndroid Build Coastguard Worker creationBounds,
1784*c8dee2aaSAndroid Build Coastguard Worker matrixRange,
1785*c8dee2aaSAndroid Build Coastguard Worker alloc));
1786*c8dee2aaSAndroid Build Coastguard Worker }
1787*c8dee2aaSAndroid Build Coastguard Worker }
1788*c8dee2aaSAndroid Build Coastguard Worker }
1789*c8dee2aaSAndroid Build Coastguard Worker #endif // !defined(SK_DISABLE_SDF_TEXT)
1790*c8dee2aaSAndroid Build Coastguard Worker
1791*c8dee2aaSAndroid Build Coastguard Worker // Direct Mask case
1792*c8dee2aaSAndroid Build Coastguard Worker // Handle all the directly mapped mask subruns.
1793*c8dee2aaSAndroid Build Coastguard Worker if (!source.empty() && !positionMatrix.hasPerspective()) {
1794*c8dee2aaSAndroid Build Coastguard Worker // Process masks including ARGB - this should be the 99.99% case.
1795*c8dee2aaSAndroid Build Coastguard Worker // This will handle medium size emoji that are sharing the run with SDFT drawn text.
1796*c8dee2aaSAndroid Build Coastguard Worker // If things are too big they will be passed along to the drawing of last resort
1797*c8dee2aaSAndroid Build Coastguard Worker // below.
1798*c8dee2aaSAndroid Build Coastguard Worker SkStrikeSpec strikeSpec = SkStrikeSpec::MakeMask(
1799*c8dee2aaSAndroid Build Coastguard Worker runFont, runPaint, deviceProps, scalerContextFlags, positionMatrix);
1800*c8dee2aaSAndroid Build Coastguard Worker
1801*c8dee2aaSAndroid Build Coastguard Worker sk_sp<StrikeForGPU> strike = strikeSpec.findOrCreateScopedStrike(strikeCache);
1802*c8dee2aaSAndroid Build Coastguard Worker
1803*c8dee2aaSAndroid Build Coastguard Worker auto acceptedBuffer = SkMakeZip(acceptedPackedGlyphIDs,
1804*c8dee2aaSAndroid Build Coastguard Worker acceptedPositions,
1805*c8dee2aaSAndroid Build Coastguard Worker acceptedFormats);
1806*c8dee2aaSAndroid Build Coastguard Worker auto [accepted, rejected, creationBounds] = prepare_for_direct_mask_drawing(
1807*c8dee2aaSAndroid Build Coastguard Worker strike.get(), positionMatrix, source, acceptedBuffer, rejectedBuffer);
1808*c8dee2aaSAndroid Build Coastguard Worker source = rejected;
1809*c8dee2aaSAndroid Build Coastguard Worker
1810*c8dee2aaSAndroid Build Coastguard Worker if (creationBehavior == kAddSubRuns && !accepted.empty()) {
1811*c8dee2aaSAndroid Build Coastguard Worker auto addGlyphsWithSameFormat =
1812*c8dee2aaSAndroid Build Coastguard Worker [&, bounds = creationBounds](
1813*c8dee2aaSAndroid Build Coastguard Worker SkZip<const SkPackedGlyphID, const SkPoint> subrun,
1814*c8dee2aaSAndroid Build Coastguard Worker MaskFormat format) {
1815*c8dee2aaSAndroid Build Coastguard Worker container->fSubRuns.append(
1816*c8dee2aaSAndroid Build Coastguard Worker DirectMaskSubRun::Make(bounds,
1817*c8dee2aaSAndroid Build Coastguard Worker subrun,
1818*c8dee2aaSAndroid Build Coastguard Worker container->initialPosition(),
1819*c8dee2aaSAndroid Build Coastguard Worker strike->strikePromise(),
1820*c8dee2aaSAndroid Build Coastguard Worker format,
1821*c8dee2aaSAndroid Build Coastguard Worker alloc));
1822*c8dee2aaSAndroid Build Coastguard Worker };
1823*c8dee2aaSAndroid Build Coastguard Worker add_multi_mask_format(addGlyphsWithSameFormat, accepted);
1824*c8dee2aaSAndroid Build Coastguard Worker }
1825*c8dee2aaSAndroid Build Coastguard Worker }
1826*c8dee2aaSAndroid Build Coastguard Worker }
1827*c8dee2aaSAndroid Build Coastguard Worker
1828*c8dee2aaSAndroid Build Coastguard Worker // Drawable case
1829*c8dee2aaSAndroid Build Coastguard Worker // Handle all the drawable glyphs - usually large or perspective color glyphs.
1830*c8dee2aaSAndroid Build Coastguard Worker if (!source.empty()) {
1831*c8dee2aaSAndroid Build Coastguard Worker auto [strikeSpec, strikeToSourceScale] =
1832*c8dee2aaSAndroid Build Coastguard Worker SkStrikeSpec::MakePath(runFont, runPaint, deviceProps, scalerContextFlags);
1833*c8dee2aaSAndroid Build Coastguard Worker
1834*c8dee2aaSAndroid Build Coastguard Worker if (!SkScalarNearlyZero(strikeToSourceScale)) {
1835*c8dee2aaSAndroid Build Coastguard Worker sk_sp<StrikeForGPU> strike = strikeSpec.findOrCreateScopedStrike(strikeCache);
1836*c8dee2aaSAndroid Build Coastguard Worker
1837*c8dee2aaSAndroid Build Coastguard Worker auto acceptedBuffer = SkMakeZip(acceptedGlyphIDs, acceptedPositions);
1838*c8dee2aaSAndroid Build Coastguard Worker auto [accepted, rejected] =
1839*c8dee2aaSAndroid Build Coastguard Worker prepare_for_drawable_drawing(strike.get(), source, acceptedBuffer, rejectedBuffer);
1840*c8dee2aaSAndroid Build Coastguard Worker source = rejected;
1841*c8dee2aaSAndroid Build Coastguard Worker
1842*c8dee2aaSAndroid Build Coastguard Worker if (creationBehavior == kAddSubRuns && !accepted.empty()) {
1843*c8dee2aaSAndroid Build Coastguard Worker container->fSubRuns.append(
1844*c8dee2aaSAndroid Build Coastguard Worker DrawableSubRun::Make(
1845*c8dee2aaSAndroid Build Coastguard Worker accepted,
1846*c8dee2aaSAndroid Build Coastguard Worker strikeToSourceScale,
1847*c8dee2aaSAndroid Build Coastguard Worker strike->strikePromise(),
1848*c8dee2aaSAndroid Build Coastguard Worker alloc));
1849*c8dee2aaSAndroid Build Coastguard Worker }
1850*c8dee2aaSAndroid Build Coastguard Worker }
1851*c8dee2aaSAndroid Build Coastguard Worker }
1852*c8dee2aaSAndroid Build Coastguard Worker
1853*c8dee2aaSAndroid Build Coastguard Worker // Path case
1854*c8dee2aaSAndroid Build Coastguard Worker // Handle path subruns. Mainly, large or large perspective glyphs with no color.
1855*c8dee2aaSAndroid Build Coastguard Worker if (!source.empty()) {
1856*c8dee2aaSAndroid Build Coastguard Worker auto [strikeSpec, strikeToSourceScale] =
1857*c8dee2aaSAndroid Build Coastguard Worker SkStrikeSpec::MakePath(runFont, runPaint, deviceProps, scalerContextFlags);
1858*c8dee2aaSAndroid Build Coastguard Worker
1859*c8dee2aaSAndroid Build Coastguard Worker if (!SkScalarNearlyZero(strikeToSourceScale)) {
1860*c8dee2aaSAndroid Build Coastguard Worker sk_sp<StrikeForGPU> strike = strikeSpec.findOrCreateScopedStrike(strikeCache);
1861*c8dee2aaSAndroid Build Coastguard Worker
1862*c8dee2aaSAndroid Build Coastguard Worker auto acceptedBuffer = SkMakeZip(acceptedGlyphIDs, acceptedPositions);
1863*c8dee2aaSAndroid Build Coastguard Worker auto [accepted, rejected] =
1864*c8dee2aaSAndroid Build Coastguard Worker prepare_for_path_drawing(strike.get(), source, acceptedBuffer, rejectedBuffer);
1865*c8dee2aaSAndroid Build Coastguard Worker source = rejected;
1866*c8dee2aaSAndroid Build Coastguard Worker
1867*c8dee2aaSAndroid Build Coastguard Worker if (creationBehavior == kAddSubRuns && !accepted.empty()) {
1868*c8dee2aaSAndroid Build Coastguard Worker const bool isAntiAliased =
1869*c8dee2aaSAndroid Build Coastguard Worker subRunControl->forcePathAA() || has_some_antialiasing(runFont);
1870*c8dee2aaSAndroid Build Coastguard Worker container->fSubRuns.append(
1871*c8dee2aaSAndroid Build Coastguard Worker PathSubRun::Make(accepted,
1872*c8dee2aaSAndroid Build Coastguard Worker isAntiAliased,
1873*c8dee2aaSAndroid Build Coastguard Worker strikeToSourceScale,
1874*c8dee2aaSAndroid Build Coastguard Worker strike->strikePromise(),
1875*c8dee2aaSAndroid Build Coastguard Worker alloc));
1876*c8dee2aaSAndroid Build Coastguard Worker }
1877*c8dee2aaSAndroid Build Coastguard Worker }
1878*c8dee2aaSAndroid Build Coastguard Worker }
1879*c8dee2aaSAndroid Build Coastguard Worker
1880*c8dee2aaSAndroid Build Coastguard Worker // Drawing of last resort case
1881*c8dee2aaSAndroid Build Coastguard Worker // Draw all the rest of the rejected glyphs from above. This scales out of the atlas to
1882*c8dee2aaSAndroid Build Coastguard Worker // the screen, so quality will suffer. This mainly handles large color or perspective
1883*c8dee2aaSAndroid Build Coastguard Worker // color not handled by Drawables.
1884*c8dee2aaSAndroid Build Coastguard Worker if (!source.empty() && !SkScalarNearlyZero(approximateDeviceTextSize)) {
1885*c8dee2aaSAndroid Build Coastguard Worker // Creation matrix will be changed below to meet the following criteria:
1886*c8dee2aaSAndroid Build Coastguard Worker // * No perspective - the font scaler and the strikes can't handle perspective masks.
1887*c8dee2aaSAndroid Build Coastguard Worker // * Fits atlas - creationMatrix will be conditioned so that the maximum glyph
1888*c8dee2aaSAndroid Build Coastguard Worker // dimension for this run will be < kMaxBilerpAtlasDimension.
1889*c8dee2aaSAndroid Build Coastguard Worker SkMatrix creationMatrix = positionMatrix;
1890*c8dee2aaSAndroid Build Coastguard Worker
1891*c8dee2aaSAndroid Build Coastguard Worker // Condition creationMatrix for perspective.
1892*c8dee2aaSAndroid Build Coastguard Worker if (creationMatrix.hasPerspective()) {
1893*c8dee2aaSAndroid Build Coastguard Worker // Find a scale factor that reduces pixelation caused by keystoning.
1894*c8dee2aaSAndroid Build Coastguard Worker SkPoint center = glyphRunList.sourceBounds().center();
1895*c8dee2aaSAndroid Build Coastguard Worker SkScalar maxAreaScale = SkMatrixPriv::DifferentialAreaScale(creationMatrix, center);
1896*c8dee2aaSAndroid Build Coastguard Worker SkScalar perspectiveFactor = 1;
1897*c8dee2aaSAndroid Build Coastguard Worker if (SkIsFinite(maxAreaScale) && !SkScalarNearlyZero(maxAreaScale)) {
1898*c8dee2aaSAndroid Build Coastguard Worker perspectiveFactor = SkScalarSqrt(maxAreaScale);
1899*c8dee2aaSAndroid Build Coastguard Worker }
1900*c8dee2aaSAndroid Build Coastguard Worker
1901*c8dee2aaSAndroid Build Coastguard Worker // Masks can not be created in perspective. Create a non-perspective font with a
1902*c8dee2aaSAndroid Build Coastguard Worker // scale that will support the perspective keystoning.
1903*c8dee2aaSAndroid Build Coastguard Worker creationMatrix = SkMatrix::Scale(perspectiveFactor, perspectiveFactor);
1904*c8dee2aaSAndroid Build Coastguard Worker }
1905*c8dee2aaSAndroid Build Coastguard Worker
1906*c8dee2aaSAndroid Build Coastguard Worker // Reduce to make a one pixel border for the bilerp padding.
1907*c8dee2aaSAndroid Build Coastguard Worker static const constexpr SkScalar kMaxBilerpAtlasDimension =
1908*c8dee2aaSAndroid Build Coastguard Worker SkGlyphDigest::kSkSideTooBigForAtlas - 2;
1909*c8dee2aaSAndroid Build Coastguard Worker
1910*c8dee2aaSAndroid Build Coastguard Worker // Get the raw glyph IDs to simulate device drawing to figure the maximum device
1911*c8dee2aaSAndroid Build Coastguard Worker // dimension.
1912*c8dee2aaSAndroid Build Coastguard Worker const SkSpan<const SkGlyphID> glyphs = get_glyphIDs(source);
1913*c8dee2aaSAndroid Build Coastguard Worker
1914*c8dee2aaSAndroid Build Coastguard Worker // maxGlyphDimension always returns an integer even though the return type is SkScalar.
1915*c8dee2aaSAndroid Build Coastguard Worker auto maxGlyphDimension = [&](const SkMatrix& m) {
1916*c8dee2aaSAndroid Build Coastguard Worker const SkStrikeSpec strikeSpec = SkStrikeSpec::MakeTransformMask(
1917*c8dee2aaSAndroid Build Coastguard Worker runFont, runPaint, deviceProps, scalerContextFlags, m);
1918*c8dee2aaSAndroid Build Coastguard Worker const sk_sp<StrikeForGPU> gaugingStrike =
1919*c8dee2aaSAndroid Build Coastguard Worker strikeSpec.findOrCreateScopedStrike(strikeCache);
1920*c8dee2aaSAndroid Build Coastguard Worker const SkScalar maxDimension =
1921*c8dee2aaSAndroid Build Coastguard Worker find_maximum_glyph_dimension(gaugingStrike.get(), glyphs);
1922*c8dee2aaSAndroid Build Coastguard Worker // TODO: There is a problem where a small character (say .) and a large
1923*c8dee2aaSAndroid Build Coastguard Worker // character (say M) are in the same run. If the run is scaled to be very
1924*c8dee2aaSAndroid Build Coastguard Worker // large, then the M may return 0 because its dimensions are > 65535, but
1925*c8dee2aaSAndroid Build Coastguard Worker // the small character produces regular result because its largest dimension
1926*c8dee2aaSAndroid Build Coastguard Worker // is < 65535. This will create an improper scale factor causing the M to be
1927*c8dee2aaSAndroid Build Coastguard Worker // too large to fit in the atlas. Tracked by skia:13714.
1928*c8dee2aaSAndroid Build Coastguard Worker return maxDimension;
1929*c8dee2aaSAndroid Build Coastguard Worker };
1930*c8dee2aaSAndroid Build Coastguard Worker
1931*c8dee2aaSAndroid Build Coastguard Worker // Condition the creationMatrix so that glyphs fit in the atlas.
1932*c8dee2aaSAndroid Build Coastguard Worker for (SkScalar maxDimension = maxGlyphDimension(creationMatrix);
1933*c8dee2aaSAndroid Build Coastguard Worker kMaxBilerpAtlasDimension < maxDimension;
1934*c8dee2aaSAndroid Build Coastguard Worker maxDimension = maxGlyphDimension(creationMatrix))
1935*c8dee2aaSAndroid Build Coastguard Worker {
1936*c8dee2aaSAndroid Build Coastguard Worker // The SkScalerContext has a limit of 65536 maximum dimension.
1937*c8dee2aaSAndroid Build Coastguard Worker // reductionFactor will always be < 1 because
1938*c8dee2aaSAndroid Build Coastguard Worker // maxDimension > kMaxBilerpAtlasDimension, and because maxDimension will always
1939*c8dee2aaSAndroid Build Coastguard Worker // be an integer the reduction factor will always be at most 254 / 255.
1940*c8dee2aaSAndroid Build Coastguard Worker SkScalar reductionFactor = kMaxBilerpAtlasDimension / maxDimension;
1941*c8dee2aaSAndroid Build Coastguard Worker creationMatrix.postScale(reductionFactor, reductionFactor);
1942*c8dee2aaSAndroid Build Coastguard Worker }
1943*c8dee2aaSAndroid Build Coastguard Worker
1944*c8dee2aaSAndroid Build Coastguard Worker // Draw using the creationMatrix.
1945*c8dee2aaSAndroid Build Coastguard Worker SkStrikeSpec strikeSpec = SkStrikeSpec::MakeTransformMask(
1946*c8dee2aaSAndroid Build Coastguard Worker runFont, runPaint, deviceProps, scalerContextFlags, creationMatrix);
1947*c8dee2aaSAndroid Build Coastguard Worker
1948*c8dee2aaSAndroid Build Coastguard Worker sk_sp<StrikeForGPU> strike = strikeSpec.findOrCreateScopedStrike(strikeCache);
1949*c8dee2aaSAndroid Build Coastguard Worker
1950*c8dee2aaSAndroid Build Coastguard Worker auto acceptedBuffer =
1951*c8dee2aaSAndroid Build Coastguard Worker SkMakeZip(acceptedPackedGlyphIDs, acceptedPositions, acceptedFormats);
1952*c8dee2aaSAndroid Build Coastguard Worker auto [accepted, rejected, creationBounds] =
1953*c8dee2aaSAndroid Build Coastguard Worker prepare_for_mask_drawing(
1954*c8dee2aaSAndroid Build Coastguard Worker strike.get(), creationMatrix, source, acceptedBuffer, rejectedBuffer);
1955*c8dee2aaSAndroid Build Coastguard Worker source = rejected;
1956*c8dee2aaSAndroid Build Coastguard Worker
1957*c8dee2aaSAndroid Build Coastguard Worker if (creationBehavior == kAddSubRuns && !accepted.empty()) {
1958*c8dee2aaSAndroid Build Coastguard Worker
1959*c8dee2aaSAndroid Build Coastguard Worker auto addGlyphsWithSameFormat =
1960*c8dee2aaSAndroid Build Coastguard Worker [&, bounds = creationBounds](
1961*c8dee2aaSAndroid Build Coastguard Worker SkZip<const SkPackedGlyphID, const SkPoint> subrun,
1962*c8dee2aaSAndroid Build Coastguard Worker MaskFormat format) {
1963*c8dee2aaSAndroid Build Coastguard Worker container->fSubRuns.append(
1964*c8dee2aaSAndroid Build Coastguard Worker TransformedMaskSubRun::Make(subrun,
1965*c8dee2aaSAndroid Build Coastguard Worker container->initialPosition(),
1966*c8dee2aaSAndroid Build Coastguard Worker strike->strikePromise(),
1967*c8dee2aaSAndroid Build Coastguard Worker creationMatrix,
1968*c8dee2aaSAndroid Build Coastguard Worker bounds,
1969*c8dee2aaSAndroid Build Coastguard Worker format,
1970*c8dee2aaSAndroid Build Coastguard Worker alloc));
1971*c8dee2aaSAndroid Build Coastguard Worker };
1972*c8dee2aaSAndroid Build Coastguard Worker add_multi_mask_format(addGlyphsWithSameFormat, accepted);
1973*c8dee2aaSAndroid Build Coastguard Worker }
1974*c8dee2aaSAndroid Build Coastguard Worker }
1975*c8dee2aaSAndroid Build Coastguard Worker }
1976*c8dee2aaSAndroid Build Coastguard Worker
1977*c8dee2aaSAndroid Build Coastguard Worker return container;
1978*c8dee2aaSAndroid Build Coastguard Worker }
1979*c8dee2aaSAndroid Build Coastguard Worker
draw(SkCanvas * canvas,SkPoint drawOrigin,const SkPaint & paint,const SkRefCnt * subRunStorage,const AtlasDrawDelegate & atlasDelegate) const1980*c8dee2aaSAndroid Build Coastguard Worker void SubRunContainer::draw(SkCanvas* canvas,
1981*c8dee2aaSAndroid Build Coastguard Worker SkPoint drawOrigin,
1982*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint,
1983*c8dee2aaSAndroid Build Coastguard Worker const SkRefCnt* subRunStorage,
1984*c8dee2aaSAndroid Build Coastguard Worker const AtlasDrawDelegate& atlasDelegate) const {
1985*c8dee2aaSAndroid Build Coastguard Worker for (auto& subRun : fSubRuns) {
1986*c8dee2aaSAndroid Build Coastguard Worker subRun.draw(canvas, drawOrigin, paint, sk_ref_sp(subRunStorage), atlasDelegate);
1987*c8dee2aaSAndroid Build Coastguard Worker }
1988*c8dee2aaSAndroid Build Coastguard Worker }
1989*c8dee2aaSAndroid Build Coastguard Worker
canReuse(const SkPaint & paint,const SkMatrix & positionMatrix) const1990*c8dee2aaSAndroid Build Coastguard Worker bool SubRunContainer::canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const {
1991*c8dee2aaSAndroid Build Coastguard Worker for (const SubRun& subRun : fSubRuns) {
1992*c8dee2aaSAndroid Build Coastguard Worker if (!subRun.canReuse(paint, positionMatrix)) {
1993*c8dee2aaSAndroid Build Coastguard Worker return false;
1994*c8dee2aaSAndroid Build Coastguard Worker }
1995*c8dee2aaSAndroid Build Coastguard Worker }
1996*c8dee2aaSAndroid Build Coastguard Worker return true;
1997*c8dee2aaSAndroid Build Coastguard Worker }
1998*c8dee2aaSAndroid Build Coastguard Worker
1999*c8dee2aaSAndroid Build Coastguard Worker // Returns the empty span if there is a problem reading the positions.
MakePointsFromBuffer(SkReadBuffer & buffer,SubRunAllocator * alloc)2000*c8dee2aaSAndroid Build Coastguard Worker SkSpan<SkPoint> MakePointsFromBuffer(SkReadBuffer& buffer, SubRunAllocator* alloc) {
2001*c8dee2aaSAndroid Build Coastguard Worker uint32_t glyphCount = buffer.getArrayCount();
2002*c8dee2aaSAndroid Build Coastguard Worker
2003*c8dee2aaSAndroid Build Coastguard Worker // Zero indicates a problem with serialization.
2004*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(glyphCount != 0)) { return {}; }
2005*c8dee2aaSAndroid Build Coastguard Worker
2006*c8dee2aaSAndroid Build Coastguard Worker // Check that the count will not overflow the arena.
2007*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(glyphCount <= INT_MAX &&
2008*c8dee2aaSAndroid Build Coastguard Worker BagOfBytes::WillCountFit<SkPoint>(glyphCount))) { return {}; }
2009*c8dee2aaSAndroid Build Coastguard Worker
2010*c8dee2aaSAndroid Build Coastguard Worker SkPoint* positionsData = alloc->makePODArray<SkPoint>(glyphCount);
2011*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.readPointArray(positionsData, glyphCount)) { return {}; }
2012*c8dee2aaSAndroid Build Coastguard Worker return {positionsData, glyphCount};
2013*c8dee2aaSAndroid Build Coastguard Worker }
2014*c8dee2aaSAndroid Build Coastguard Worker
2015*c8dee2aaSAndroid Build Coastguard Worker } // namespace sktext::gpu
2016