1 /*
2 * Copyright 2019 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/core/SkAlphaType.h"
9 #include "include/core/SkColor.h"
10 #include "include/core/SkMaskFilter.h"
11 #include "include/core/SkMatrix.h"
12 #include "include/core/SkPaint.h"
13 #include "include/core/SkPath.h"
14 #include "include/core/SkPixmap.h"
15 #include "include/core/SkPoint.h"
16 #include "include/core/SkRSXform.h"
17 #include "include/core/SkRect.h"
18 #include "include/core/SkRefCnt.h"
19 #include "include/core/SkScalar.h"
20 #include "include/core/SkShader.h"
21 #include "include/core/SkSurfaceProps.h"
22 #include "src/base/SkArenaAlloc.h"
23 #include "src/core/SkBlendModePriv.h"
24 #include "src/core/SkBlenderBase.h"
25 #include "src/core/SkColorSpacePriv.h"
26 #include "src/core/SkColorSpaceXformSteps.h"
27 #include "src/core/SkCoreBlitters.h"
28 #include "src/core/SkDraw.h"
29 #include "src/core/SkEffectPriv.h"
30 #include "src/core/SkRasterClip.h"
31 #include "src/core/SkRasterPipeline.h"
32 #include "src/core/SkRasterPipelineOpContexts.h"
33 #include "src/core/SkRasterPipelineOpList.h"
34 #include "src/core/SkScan.h"
35 #include "src/core/SkSurfacePriv.h"
36 #include "src/shaders/SkShaderBase.h"
37 #include "src/shaders/SkTransformShader.h"
38
39 #include <cstdint>
40 #include <optional>
41
42 class SkBlender;
43 class SkBlitter;
44 enum class SkBlendMode;
45
fill_rect(const SkMatrix & ctm,const SkRasterClip & rc,const SkRect & r,SkBlitter * blitter,SkPath * scratchPath)46 static void fill_rect(const SkMatrix& ctm, const SkRasterClip& rc,
47 const SkRect& r, SkBlitter* blitter, SkPath* scratchPath) {
48 if (ctm.rectStaysRect()) {
49 SkRect dr;
50 ctm.mapRect(&dr, r);
51 SkScan::FillRect(dr, rc, blitter);
52 } else {
53 SkPoint pts[4];
54 r.toQuad(pts);
55 ctm.mapPoints(pts, pts, 4);
56
57 scratchPath->rewind();
58 scratchPath->addPoly(pts, 4, true);
59 SkScan::FillPath(*scratchPath, rc, blitter);
60 }
61 }
62
load_color(SkRasterPipeline_UniformColorCtx * ctx,const float rgba[])63 static void load_color(SkRasterPipeline_UniformColorCtx* ctx, const float rgba[]) {
64 // only need one of these. can I query the pipeline to know if its lowp or highp?
65 ctx->rgba[0] = SkScalarRoundToInt(rgba[0]*255); ctx->r = rgba[0];
66 ctx->rgba[1] = SkScalarRoundToInt(rgba[1]*255); ctx->g = rgba[1];
67 ctx->rgba[2] = SkScalarRoundToInt(rgba[2]*255); ctx->b = rgba[2];
68 ctx->rgba[3] = SkScalarRoundToInt(rgba[3]*255); ctx->a = rgba[3];
69 }
70
drawAtlas(const SkRSXform xform[],const SkRect textures[],const SkColor colors[],int count,sk_sp<SkBlender> blender,const SkPaint & paint)71 void SkDraw::drawAtlas(const SkRSXform xform[],
72 const SkRect textures[],
73 const SkColor colors[],
74 int count,
75 sk_sp<SkBlender> blender,
76 const SkPaint& paint) {
77 sk_sp<SkShader> atlasShader = paint.refShader();
78 if (!atlasShader) {
79 return;
80 }
81
82 SkSTArenaAlloc<256> alloc;
83
84 SkPaint p(paint);
85 p.setAntiAlias(false); // we never respect this for drawAtlas(or drawVertices)
86 p.setStyle(SkPaint::kFill_Style);
87 p.setShader(nullptr);
88 p.setMaskFilter(nullptr);
89
90 // The RSXForms can't contain perspective - only the CTM can.
91 const bool perspective = fCTM->hasPerspective();
92
93 auto transformShader = alloc.make<SkTransformShader>(*as_SB(atlasShader), perspective);
94
95 SkRasterPipeline pipeline(&alloc);
96 SkSurfaceProps props = SkSurfacePropsCopyOrDefault(fProps);
97 SkStageRec rec = {&pipeline, &alloc, fDst.colorType(), fDst.colorSpace(),
98 p.getColor4f(), props};
99 // We pass an identity matrix here rather than the CTM. The CTM gets folded into the
100 // per-triangle matrix.
101 if (!as_SB(transformShader)->appendRootStages(rec, SkMatrix::I())) {
102 return;
103 }
104
105 SkRasterPipeline_UniformColorCtx* uniformCtx = nullptr;
106 SkColorSpaceXformSteps steps(sk_srgb_singleton(), kUnpremul_SkAlphaType,
107 rec.fDstCS, kUnpremul_SkAlphaType);
108 if (colors) {
109 // we will late-bind the values in ctx, once for each color in the loop
110 uniformCtx = alloc.make<SkRasterPipeline_UniformColorCtx>();
111 rec.fPipeline->append(SkRasterPipelineOp::uniform_color_dst, uniformCtx);
112 std::optional<SkBlendMode> bm = as_BB(blender)->asBlendMode();
113 if (!bm.has_value()) {
114 return;
115 }
116 SkBlendMode_AppendStages(*bm, rec.fPipeline);
117 }
118
119 bool isOpaque = !colors && transformShader->isOpaque();
120 if (p.getAlphaf() != 1) {
121 rec.fPipeline->append(SkRasterPipelineOp::scale_1_float, alloc.make<float>(p.getAlphaf()));
122 isOpaque = false;
123 }
124
125 auto blitter = SkCreateRasterPipelineBlitter(fDst, p, pipeline, isOpaque, &alloc,
126 fRC->clipShader());
127 if (!blitter) {
128 return;
129 }
130 SkPath scratchPath;
131
132 for (int i = 0; i < count; ++i) {
133 if (colors) {
134 SkColor4f c4 = SkColor4f::FromColor(colors[i]);
135 steps.apply(c4.vec());
136 load_color(uniformCtx, c4.premul().vec());
137 }
138
139 SkMatrix mx;
140 mx.setRSXform(xform[i]);
141 mx.preTranslate(-textures[i].fLeft, -textures[i].fTop);
142 mx.postConcat(*fCTM);
143 SkMatrix inv;
144 if (!mx.invert(&inv)) {
145 return;
146 }
147 if (transformShader->update(inv)) {
148 fill_rect(mx, *fRC, textures[i], blitter, &scratchPath);
149 }
150 }
151 }
152