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
23static 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
40static 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
48void 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