Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkPictureShader.cpp
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                                  const SkMatrix* localMatrix)
23     : INHERITED(localMatrix)
24     , fPicture(SkRef(picture))
25     , fTmx(tmx)
26     , fTmy(tmy) { }
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     fPicture = SkPicture::CreateFromBuffer(buffer);
33 }
34
35 SkPictureShader::~SkPictureShader() {
36     fPicture->unref();
37 }
38
39 SkPictureShader* SkPictureShader::Create(SkPicture* picture, TileMode tmx, TileMode tmy,
40                                          const SkMatrix* localMatrix) {
41     if (!picture || 0 == picture->width() || 0 == picture->height()) {
42         return NULL;
43     }
44     return SkNEW_ARGS(SkPictureShader, (picture, tmx, tmy, localMatrix));
45 }
46
47 void SkPictureShader::flatten(SkWriteBuffer& buffer) const {
48     this->INHERITED::flatten(buffer);
49
50     buffer.write32(fTmx);
51     buffer.write32(fTmy);
52     fPicture->flatten(buffer);
53 }
54
55 SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix, const SkMatrix* localM) const {
56     SkASSERT(fPicture && fPicture->width() > 0 && fPicture->height() > 0);
57
58     SkMatrix m;
59     if (this->hasLocalMatrix()) {
60         m.setConcat(matrix, this->getLocalMatrix());
61     } else {
62         m = matrix;
63     }
64     if (localM) {
65         m.preConcat(*localM);
66     }
67
68     // Use a rotation-invariant scale
69     SkPoint scale;
70     if (!SkDecomposeUpper2x2(m, NULL, &scale, NULL)) {
71         // Decomposition failed, use an approximation.
72         scale.set(SkScalarSqrt(m.getScaleX() * m.getScaleX() + m.getSkewX() * m.getSkewX()),
73                   SkScalarSqrt(m.getScaleY() * m.getScaleY() + m.getSkewY() * m.getSkewY()));
74     }
75     SkSize scaledSize = SkSize::Make(scale.x() * fPicture->width(), scale.y() * fPicture->height());
76
77     SkISize tileSize = scaledSize.toRound();
78     if (tileSize.isEmpty()) {
79         return NULL;
80     }
81
82     // The actual scale, compensating for rounding.
83     SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fPicture->width(),
84                                     SkIntToScalar(tileSize.height()) / fPicture->height());
85
86     SkAutoMutexAcquire ama(fCachedBitmapShaderMutex);
87
88     // TODO(fmalita): remove fCachedLocalMatrix from this key after getLocalMatrix is removed.
89     if (!fCachedBitmapShader || tileScale != fCachedTileScale ||
90         this->getLocalMatrix() != fCachedLocalMatrix) {
91         SkBitmap bm;
92         if (!bm.allocN32Pixels(tileSize.width(), tileSize.height())) {
93             return NULL;
94         }
95         bm.eraseColor(SK_ColorTRANSPARENT);
96
97         SkCanvas canvas(bm);
98         canvas.scale(tileScale.width(), tileScale.height());
99         canvas.drawPicture(*fPicture);
100
101         fCachedTileScale = tileScale;
102         fCachedLocalMatrix = this->getLocalMatrix();
103
104         SkMatrix shaderMatrix = this->getLocalMatrix();
105         shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height());
106         fCachedBitmapShader.reset(CreateBitmapShader(bm, fTmx, fTmy, &shaderMatrix));
107     }
108
109     // Increment the ref counter inside the mutex to ensure the returned pointer is still valid.
110     // Otherwise, the pointer may have been overwritten on a different thread before the object's
111     // ref count was incremented.
112     fCachedBitmapShader.get()->ref();
113     return fCachedBitmapShader;
114 }
115
116 size_t SkPictureShader::contextSize() const {
117     return sizeof(PictureShaderContext);
118 }
119
120 SkShader::Context* SkPictureShader::onCreateContext(const ContextRec& rec, void* storage) const {
121     SkAutoTUnref<SkShader> bitmapShader(this->refBitmapShader(*rec.fMatrix, rec.fLocalMatrix));
122     if (NULL == bitmapShader.get()) {
123         return NULL;
124     }
125     return PictureShaderContext::Create(storage, *this, rec, bitmapShader);
126 }
127
128 /////////////////////////////////////////////////////////////////////////////////////////
129
130 SkShader::Context* SkPictureShader::PictureShaderContext::Create(void* storage,
131                    const SkPictureShader& shader, const ContextRec& rec, SkShader* bitmapShader) {
132     PictureShaderContext* ctx = SkNEW_PLACEMENT_ARGS(storage, PictureShaderContext,
133                                                      (shader, rec, bitmapShader));
134     if (NULL == ctx->fBitmapShaderContext) {
135         ctx->~PictureShaderContext();
136         ctx = NULL;
137     }
138     return ctx;
139 }
140
141 SkPictureShader::PictureShaderContext::PictureShaderContext(
142         const SkPictureShader& shader, const ContextRec& rec, SkShader* bitmapShader)
143     : INHERITED(shader, rec)
144     , fBitmapShader(SkRef(bitmapShader))
145 {
146     fBitmapShaderContextStorage = sk_malloc_throw(bitmapShader->contextSize());
147     fBitmapShaderContext = bitmapShader->createContext(rec, fBitmapShaderContextStorage);
148     //if fBitmapShaderContext is null, we are invalid
149 }
150
151 SkPictureShader::PictureShaderContext::~PictureShaderContext() {
152     if (fBitmapShaderContext) {
153         fBitmapShaderContext->~Context();
154     }
155     sk_free(fBitmapShaderContextStorage);
156 }
157
158 uint32_t SkPictureShader::PictureShaderContext::getFlags() const {
159     SkASSERT(fBitmapShaderContext);
160     return fBitmapShaderContext->getFlags();
161 }
162
163 SkShader::Context::ShadeProc SkPictureShader::PictureShaderContext::asAShadeProc(void** ctx) {
164     SkASSERT(fBitmapShaderContext);
165     return fBitmapShaderContext->asAShadeProc(ctx);
166 }
167
168 void SkPictureShader::PictureShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
169     SkASSERT(fBitmapShaderContext);
170     fBitmapShaderContext->shadeSpan(x, y, dstC, count);
171 }
172
173 void SkPictureShader::PictureShaderContext::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
174     SkASSERT(fBitmapShaderContext);
175     fBitmapShaderContext->shadeSpan16(x, y, dstC, count);
176 }
177
178 #ifndef SK_IGNORE_TO_STRING
179 void SkPictureShader::toString(SkString* str) const {
180     static const char* gTileModeName[SkShader::kTileModeCount] = {
181         "clamp", "repeat", "mirror"
182     };
183
184     str->appendf("PictureShader: [%d:%d] ",
185                  fPicture ? fPicture->width() : 0,
186                  fPicture ? fPicture->height() : 0);
187
188     str->appendf("(%s, %s)", gTileModeName[fTmx], gTileModeName[fTmy]);
189
190     this->INHERITED::toString(str);
191 }
192 #endif
193
194 #if SK_SUPPORT_GPU
195 GrEffectRef* SkPictureShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
196     SkAutoTUnref<SkShader> bitmapShader(this->refBitmapShader(context->getMatrix(), NULL));
197     if (!bitmapShader) {
198         return NULL;
199     }
200     return bitmapShader->asNewEffect(context, paint);
201 }
202 #endif