OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright 2014 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 "SkPictureShader.h" | |
9 | |
10 #include "SkBitmap.h" | |
11 #include "SkBitmapProcShader.h" | |
12 #include "SkCanvas.h" | |
13 #include "SkMatrixUtils.h" | |
14 #include "SkPicture.h" | |
15 #include "SkReadBuffer.h" | |
16 | |
17 #if SK_SUPPORT_GPU | |
18 #include "GrContext.h" | |
19 #endif | |
20 | |
21 SkPictureShader::SkPictureShader(SkPicture* picture, TileMode tmx, TileMode tmy) | |
22 : fPicture(picture) | |
23 , fTmx(tmx) | |
24 , fTmy(tmy) { | |
25 SkSafeRef(fPicture); | |
26 } | |
27 | |
28 SkPictureShader::SkPictureShader(SkReadBuffer& buffer) | |
29 : INHERITED(buffer) { | |
30 fTmx = static_cast<SkShader::TileMode>(buffer.read32()); | |
31 fTmy = static_cast<SkShader::TileMode>(buffer.read32()); | |
32 if (buffer.readBool()) { | |
33 fPicture = SkPicture::CreateFromBuffer(buffer); | |
34 } else { | |
35 fPicture = NULL; | |
36 } | |
37 } | |
38 | |
39 SkPictureShader::~SkPictureShader() { | |
40 SkSafeUnref(fPicture); | |
41 } | |
42 | |
43 SkPictureShader* SkPictureShader::Create(SkPicture* picture, TileMode tmx, TileM ode tmy) { | |
44 return SkNEW_ARGS(SkPictureShader, (picture, tmx, tmy)); | |
45 } | |
46 | |
47 void SkPictureShader::flatten(SkWriteBuffer& buffer) const { | |
48 this->INHERITED::flatten(buffer); | |
49 | |
50 buffer.write32(fTmx); | |
51 buffer.write32(fTmy); | |
52 buffer.writeBool(NULL != fPicture); | |
53 if (fPicture) { | |
54 fPicture->flatten(buffer); | |
55 } | |
56 } | |
57 | |
58 bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const { | |
59 if (!fPicture || (0 == fPicture->width() && 0 == fPicture->height())) { | |
scroggo
2014/04/11 15:23:15
It appears that if the picture is NULL or it has z
f(malita)
2014/04/11 16:05:18
Good point. After making the constructor private,
| |
60 return false; | |
61 } | |
62 | |
63 SkMatrix m; | |
64 if (this->hasLocalMatrix()) { | |
65 m.setConcat(matrix, this->getLocalMatrix()); | |
66 } else { | |
67 m = matrix; | |
68 } | |
69 | |
70 // Use a rotation-invariant scale | |
71 SkPoint scale; | |
72 if (!SkDecomposeUpper2x2(m, NULL, &scale, NULL)) { | |
73 // Decomposition failed, use an approximation. | |
74 scale.set(SkScalarSqrt(m.getScaleX() * m.getScaleX() + m.getSkewX() * m. getSkewX()), | |
75 SkScalarSqrt(m.getScaleY() * m.getScaleY() + m.getSkewY() * m. getSkewY())); | |
76 } | |
77 SkSize scaledSize = SkSize::Make(scale.x() * fPicture->width(), scale.y() * fPicture->height()); | |
78 | |
79 SkISize tileSize = scaledSize.toRound(); | |
80 if (tileSize.isEmpty()) { | |
81 return false; | |
82 } | |
83 | |
84 // The actual scale, compensating for rounding. | |
85 SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fPicture-> width(), | |
86 SkIntToScalar(tileSize.height()) / fPicture- >height()); | |
87 | |
88 if (!fCachedShader || tileScale != fCachedTileScale) { | |
89 SkBitmap bm; | |
90 if (!bm.allocN32Pixels(tileSize.width(), tileSize.height())) { | |
91 return false; | |
92 } | |
93 bm.eraseColor(SK_ColorTRANSPARENT); | |
94 | |
95 SkCanvas canvas(bm); | |
96 canvas.scale(tileScale.width(), tileScale.height()); | |
97 canvas.drawPicture(*fPicture); | |
98 | |
99 fCachedShader.reset(CreateBitmapShader(bm, fTmx, fTmy)); | |
100 fCachedTileScale = tileScale; | |
101 } | |
102 | |
103 SkMatrix shaderMatrix = this->getLocalMatrix(); | |
104 shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height()); | |
105 fCachedShader->setLocalMatrix(shaderMatrix); | |
106 | |
107 return true; | |
108 } | |
109 | |
110 bool SkPictureShader::setContext(const SkBitmap& device, | |
111 const SkPaint& paint, | |
112 const SkMatrix& matrix) { | |
113 if (!this->buildBitmapShader(matrix)) { | |
114 return false; | |
115 } | |
116 | |
117 if (!this->INHERITED::setContext(device, paint, matrix)) { | |
118 return false; | |
119 } | |
120 | |
121 SkASSERT(fCachedShader); | |
122 if (!fCachedShader->setContext(device, paint, matrix)) { | |
123 this->INHERITED::endContext(); | |
124 return false; | |
125 } | |
126 | |
127 return true; | |
128 } | |
129 | |
130 void SkPictureShader::endContext() { | |
131 SkASSERT(fCachedShader); | |
132 fCachedShader->endContext(); | |
133 | |
134 this->INHERITED::endContext(); | |
135 } | |
136 | |
137 uint32_t SkPictureShader::getFlags() { | |
138 if (NULL != fCachedShader) { | |
139 return fCachedShader->getFlags(); | |
140 } | |
141 return 0; | |
142 } | |
143 | |
144 SkShader::ShadeProc SkPictureShader::asAShadeProc(void** ctx) { | |
145 if (fCachedShader) { | |
146 return fCachedShader->asAShadeProc(ctx); | |
147 } | |
148 return NULL; | |
149 } | |
150 | |
151 void SkPictureShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { | |
152 SkASSERT(fCachedShader); | |
153 fCachedShader->shadeSpan(x, y, dstC, count); | |
154 } | |
155 | |
156 void SkPictureShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) { | |
157 SkASSERT(fCachedShader); | |
158 fCachedShader->shadeSpan16(x, y, dstC, count); | |
159 } | |
160 | |
161 #ifndef SK_IGNORE_TO_STRING | |
162 void SkPictureShader::toString(SkString* str) const { | |
163 static const char* gTileModeName[SkShader::kTileModeCount] = { | |
164 "clamp", "repeat", "mirror" | |
165 }; | |
166 | |
167 str->appendf("PictureShader: [%d:%d] ", | |
168 fPicture ? fPicture->width() : 0, | |
169 fPicture ? fPicture->height() : 0); | |
170 | |
171 str->appendf("(%s, %s)", gTileModeName[fTmx], gTileModeName[fTmy]); | |
172 | |
173 this->INHERITED::toString(str); | |
174 } | |
175 #endif | |
176 | |
177 #if SK_SUPPORT_GPU | |
178 GrEffectRef* SkPictureShader::asNewEffect(GrContext* context, const SkPaint& pai nt) const { | |
179 if (!this->buildBitmapShader(context->getMatrix())) { | |
180 return NULL; | |
181 } | |
182 SkASSERT(fCachedShader); | |
183 return fCachedShader->asNewEffect(context, paint); | |
184 } | |
185 #endif | |
OLD | NEW |