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/SkColorFilter.h"
9 #include "include/core/SkRSXform.h"
10 #include "src/core/SkBlendModePriv.h"
11 #include "src/core/SkColorSpacePriv.h"
12 #include "src/core/SkColorSpaceXformSteps.h"
13 #include "src/core/SkCoreBlitters.h"
14 #include "src/core/SkDraw.h"
15 #include "src/core/SkRasterClip.h"
16 #include "src/core/SkRasterPipeline.h"
17 #include "src/core/SkScan.h"
18 #include "src/shaders/SkShaderBase.h"
19 
20 #include "include/core/SkMatrix.h"
21 #include "src/core/SkScan.h"
22 
fill_rect(const SkMatrix & ctm,const SkRasterClip & rc,const SkRect & r,SkBlitter * blitter,SkPath * scratchPath)23 static void fill_rect(const SkMatrix& ctm, const SkRasterClip& rc,
24                       const SkRect& r, SkBlitter* blitter, SkPath* scratchPath) {
25     if (ctm.rectStaysRect()) {
26         SkRect dr;
27         ctm.mapRect(&dr, r);
28         SkScan::FillRect(dr, rc, blitter);
29     } else {
30         SkPoint pts[4];
31         r.toQuad(pts);
32         ctm.mapPoints(pts, pts, 4);
33 
34         scratchPath->rewind();
35         scratchPath->addPoly(pts, 4, true);
36         SkScan::FillPath(*scratchPath, rc, blitter);
37     }
38 }
39 
load_color(SkRasterPipeline_UniformColorCtx * ctx,const float rgba[])40 static void load_color(SkRasterPipeline_UniformColorCtx* ctx, const float rgba[]) {
41     // only need one of these. can I query the pipeline to know if its lowp or highp?
42     ctx->rgba[0] = SkScalarRoundToInt(rgba[0]*255); ctx->r = rgba[0];
43     ctx->rgba[1] = SkScalarRoundToInt(rgba[1]*255); ctx->g = rgba[1];
44     ctx->rgba[2] = SkScalarRoundToInt(rgba[2]*255); ctx->b = rgba[2];
45     ctx->rgba[3] = SkScalarRoundToInt(rgba[3]*255); ctx->a = rgba[3];
46 }
47 
drawAtlas(const SkImage * atlas,const SkRSXform xform[],const SkRect textures[],const SkColor colors[],int count,SkBlendMode bmode,const SkPaint & paint)48 void SkDraw::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect textures[],
49                        const SkColor colors[], int count, SkBlendMode bmode, const SkPaint& paint) {
50     sk_sp<SkShader> atlasShader = atlas->makeShader();
51     if (!atlasShader) {
52         return;
53     }
54 
55     SkPaint p(paint);
56     p.setAntiAlias(false);  // we never respect this for drawAtlas(or drawVertices)
57     p.setStyle(SkPaint::kFill_Style);
58     p.setShader(nullptr);
59     p.setMaskFilter(nullptr);
60 
61     SkSTArenaAlloc<256> alloc;
62     SkRasterPipeline pipeline(&alloc);
63     SkStageRec rec = {
64         &pipeline, &alloc, fDst.colorType(), fDst.colorSpace(), p, nullptr, *fMatrix
65     };
66 
67     SkStageUpdater* updator = as_SB(atlasShader.get())->appendUpdatableStages(rec);
68     if (!updator) {
69         SkDraw draw(*this);
70 
71         p.setShader(atlasShader);
72         for (int i = 0; i < count; ++i) {
73             if (colors) {
74                 p.setShader(SkShaders::Blend(bmode, SkShaders::Color(colors[i]), atlasShader));
75             }
76             SkMatrix mx;
77             mx.setRSXform(xform[i]);
78             mx.preTranslate(-textures[i].fLeft, -textures[i].fTop);
79             mx.postConcat(*fMatrix);
80             draw.fMatrix = &mx;
81             draw.drawRect(textures[i], p);
82         }
83         return;
84     }
85 
86     SkRasterPipeline_UniformColorCtx* uniformCtx = nullptr;
87     SkColorSpaceXformSteps steps(sk_srgb_singleton(), kUnpremul_SkAlphaType,
88                                  rec.fDstCS,          kUnpremul_SkAlphaType);
89 
90     if (colors) {
91         // we will late-bind the values in ctx, once for each color in the loop
92         uniformCtx = alloc.make<SkRasterPipeline_UniformColorCtx>();
93         rec.fPipeline->append(SkRasterPipeline::uniform_color_dst, uniformCtx);
94         SkBlendMode_AppendStages(bmode, rec.fPipeline);
95     }
96 
97     bool isOpaque = !colors && atlasShader->isOpaque();
98     if (p.getAlphaf() != 1) {
99         rec.fPipeline->append(SkRasterPipeline::scale_1_float, alloc.make<float>(p.getAlphaf()));
100         isOpaque = false;
101     }
102 
103     auto blitter = SkCreateRasterPipelineBlitter(fDst, p, pipeline, isOpaque, &alloc,
104                                                  fRC->clipShader());
105     SkPath scratchPath;
106 
107     for (int i = 0; i < count; ++i) {
108         if (colors) {
109             SkColor4f c4 = SkColor4f::FromColor(colors[i]);
110             steps.apply(c4.vec());
111             load_color(uniformCtx, c4.premul().vec());
112         }
113 
114         SkMatrix mx;
115         mx.setRSXform(xform[i]);
116         mx.preTranslate(-textures[i].fLeft, -textures[i].fTop);
117         mx.postConcat(*fMatrix);
118 
119         updator->update(mx, nullptr);
120         fill_rect(mx, *fRC, textures[i], blitter, &scratchPath);
121     }
122 }
123