Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
2 /*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8 #include "SkColorPriv.h"
9 #include "SkReadBuffer.h"
10 #include "SkWriteBuffer.h"
11 #include "SkPixelRef.h"
12 #include "SkErrorInternals.h"
13 #include "SkBitmapProcShader.h"
15 #if SK_SUPPORT_GPU
16 #include "effects/GrSimpleTextureEffect.h"
17 #include "effects/GrBicubicEffect.h"
18 #endif
20 bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
21 switch (bm.colorType()) {
22 case kAlpha_8_SkColorType:
23 case kRGB_565_SkColorType:
24 case kIndex_8_SkColorType:
25 case kPMColor_SkColorType:
26 // if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
27 return true;
28 default:
29 break;
30 }
31 return false;
32 }
34 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
35 TileMode tmx, TileMode tmy) {
36 fRawBitmap = src;
37 fState.fTileModeX = (uint8_t)tmx;
38 fState.fTileModeY = (uint8_t)tmy;
39 fFlags = 0; // computed in setContext
40 }
42 SkBitmapProcShader::SkBitmapProcShader(SkReadBuffer& buffer)
43 : INHERITED(buffer) {
44 buffer.readBitmap(&fRawBitmap);
45 fRawBitmap.setImmutable();
46 fState.fTileModeX = buffer.readUInt();
47 fState.fTileModeY = buffer.readUInt();
48 fFlags = 0; // computed in setContext
49 }
51 SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
52 SkMatrix* texM,
53 TileMode xy[]) const {
54 if (texture) {
55 *texture = fRawBitmap;
56 }
57 if (texM) {
58 texM->reset();
59 }
60 if (xy) {
61 xy[0] = (TileMode)fState.fTileModeX;
62 xy[1] = (TileMode)fState.fTileModeY;
63 }
64 return kDefault_BitmapType;
65 }
67 void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const {
68 this->INHERITED::flatten(buffer);
70 buffer.writeBitmap(fRawBitmap);
71 buffer.writeUInt(fState.fTileModeX);
72 buffer.writeUInt(fState.fTileModeY);
73 }
75 static bool only_scale_and_translate(const SkMatrix& matrix) {
76 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
77 return (matrix.getType() & ~mask) == 0;
78 }
80 bool SkBitmapProcShader::isOpaque() const {
81 return fRawBitmap.isOpaque();
82 }
84 static bool valid_for_drawing(const SkBitmap& bm) {
85 if (0 == bm.width() || 0 == bm.height()) {
86 return false; // nothing to draw
87 }
88 if (NULL == bm.pixelRef()) {
89 return false; // no pixels to read
90 }
91 if (kIndex_8_SkColorType == bm.colorType()) {
92 // ugh, I have to lock-pixels to inspect the colortable
93 SkAutoLockPixels alp(bm);
94 if (!bm.getColorTable()) {
95 return false;
96 }
97 }
98 return true;
99 }
101 bool SkBitmapProcShader::setContext(const SkBitmap& device,
102 const SkPaint& paint,
103 const SkMatrix& matrix) {
104 if (!fRawBitmap.getTexture() && !valid_for_drawing(fRawBitmap)) {
105 return false;
106 }
108 // do this first, so we have a correct inverse matrix
109 if (!this->INHERITED::setContext(device, paint, matrix)) {
110 return false;
111 }
113 fState.fOrigBitmap = fRawBitmap;
114 if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
115 this->INHERITED::endContext();
116 return false;
117 }
119 const SkBitmap& bitmap = *fState.fBitmap;
120 bool bitmapIsOpaque = bitmap.isOpaque();
122 // update fFlags
123 uint32_t flags = 0;
124 if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
125 flags |= kOpaqueAlpha_Flag;
126 }
128 switch (bitmap.colorType()) {
129 case kRGB_565_SkColorType:
130 flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
131 break;
132 case kIndex_8_SkColorType:
133 case kPMColor_SkColorType:
134 if (bitmapIsOpaque) {
135 flags |= kHasSpan16_Flag;
136 }
137 break;
138 case kAlpha_8_SkColorType:
139 break; // never set kHasSpan16_Flag
140 default:
141 break;
142 }
144 if (paint.isDither() && bitmap.colorType() != kRGB_565_SkColorType) {
145 // gradients can auto-dither in their 16bit sampler, but we don't so
146 // we clear the flag here.
147 flags &= ~kHasSpan16_Flag;
148 }
150 // if we're only 1-pixel high, and we don't rotate, then we can claim this
151 if (1 == bitmap.height() &&
152 only_scale_and_translate(this->getTotalInverse())) {
153 flags |= kConstInY32_Flag;
154 if (flags & kHasSpan16_Flag) {
155 flags |= kConstInY16_Flag;
156 }
157 }
159 fFlags = flags;
160 return true;
161 }
163 void SkBitmapProcShader::endContext() {
164 fState.endContext();
165 this->INHERITED::endContext();
166 }
168 #define BUF_MAX 128
170 #define TEST_BUFFER_OVERRITEx
172 #ifdef TEST_BUFFER_OVERRITE
173 #define TEST_BUFFER_EXTRA 32
174 #define TEST_PATTERN 0x88888888
175 #else
176 #define TEST_BUFFER_EXTRA 0
177 #endif
179 void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
180 const SkBitmapProcState& state = fState;
181 if (state.getShaderProc32()) {
182 state.getShaderProc32()(state, x, y, dstC, count);
183 return;
184 }
186 uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
187 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc();
188 SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
189 int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
191 SkASSERT(state.fBitmap->getPixels());
192 SkASSERT(state.fBitmap->pixelRef() == NULL ||
193 state.fBitmap->pixelRef()->isLocked());
195 for (;;) {
196 int n = count;
197 if (n > max) {
198 n = max;
199 }
200 SkASSERT(n > 0 && n < BUF_MAX*2);
201 #ifdef TEST_BUFFER_OVERRITE
202 for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
203 buffer[BUF_MAX + i] = TEST_PATTERN;
204 }
205 #endif
206 mproc(state, buffer, n, x, y);
207 #ifdef TEST_BUFFER_OVERRITE
208 for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
209 SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
210 }
211 #endif
212 sproc(state, buffer, n, dstC);
214 if ((count -= n) == 0) {
215 break;
216 }
217 SkASSERT(count > 0);
218 x += n;
219 dstC += n;
220 }
221 }
223 SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) {
224 if (fState.getShaderProc32()) {
225 *ctx = &fState;
226 return (ShadeProc)fState.getShaderProc32();
227 }
228 return NULL;
229 }
231 void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
232 const SkBitmapProcState& state = fState;
233 if (state.getShaderProc16()) {
234 state.getShaderProc16()(state, x, y, dstC, count);
235 return;
236 }
238 uint32_t buffer[BUF_MAX];
239 SkBitmapProcState::MatrixProc mproc = state.getMatrixProc();
240 SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
241 int max = fState.maxCountForBufferSize(sizeof(buffer));
243 SkASSERT(state.fBitmap->getPixels());
244 SkASSERT(state.fBitmap->pixelRef() == NULL ||
245 state.fBitmap->pixelRef()->isLocked());
247 for (;;) {
248 int n = count;
249 if (n > max) {
250 n = max;
251 }
252 mproc(state, buffer, n, x, y);
253 sproc(state, buffer, n, dstC);
255 if ((count -= n) == 0) {
256 break;
257 }
258 x += n;
259 dstC += n;
260 }
261 }
263 ///////////////////////////////////////////////////////////////////////////////
265 #include "SkUnPreMultiply.h"
266 #include "SkColorShader.h"
267 #include "SkEmptyShader.h"
269 // returns true and set color if the bitmap can be drawn as a single color
270 // (for efficiency)
271 static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
272 if (1 != bm.width() || 1 != bm.height()) {
273 return false;
274 }
276 SkAutoLockPixels alp(bm);
277 if (!bm.readyToDraw()) {
278 return false;
279 }
281 switch (bm.colorType()) {
282 case kPMColor_SkColorType:
283 *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
284 return true;
285 case kRGB_565_SkColorType:
286 *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
287 return true;
288 case kIndex_8_SkColorType:
289 *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
290 return true;
291 default: // just skip the other configs for now
292 break;
293 }
294 return false;
295 }
297 static bool bitmapIsTooBig(const SkBitmap& bm) {
298 // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
299 // communicates between its matrix-proc and its sampler-proc. Until we can
300 // widen that, we have to reject bitmaps that are larger.
301 //
302 const int maxSize = 65535;
304 return bm.width() > maxSize || bm.height() > maxSize;
305 }
307 SkShader* CreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
308 SkShader::TileMode tmy, SkTBlitterAllocator* allocator) {
309 SkShader* shader;
310 SkColor color;
311 if (src.isNull() || bitmapIsTooBig(src)) {
312 if (NULL == allocator) {
313 shader = SkNEW(SkEmptyShader);
314 } else {
315 shader = allocator->createT<SkEmptyShader>();
316 }
317 }
318 else if (canUseColorShader(src, &color)) {
319 if (NULL == allocator) {
320 shader = SkNEW_ARGS(SkColorShader, (color));
321 } else {
322 shader = allocator->createT<SkColorShader>(color);
323 }
324 } else {
325 if (NULL == allocator) {
326 shader = SkNEW_ARGS(SkBitmapProcShader, (src, tmx, tmy));
327 } else {
328 shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy);
329 }
330 }
331 return shader;
332 }
334 ///////////////////////////////////////////////////////////////////////////////
336 #ifndef SK_IGNORE_TO_STRING
337 void SkBitmapProcShader::toString(SkString* str) const {
338 static const char* gTileModeName[SkShader::kTileModeCount] = {
339 "clamp", "repeat", "mirror"
340 };
342 str->append("BitmapShader: (");
344 str->appendf("(%s, %s)",
345 gTileModeName[fState.fTileModeX],
346 gTileModeName[fState.fTileModeY]);
348 str->append(" ");
349 fRawBitmap.toString(str);
351 this->INHERITED::toString(str);
353 str->append(")");
354 }
355 #endif
357 ///////////////////////////////////////////////////////////////////////////////
359 #if SK_SUPPORT_GPU
361 #include "GrTextureAccess.h"
362 #include "effects/GrSimpleTextureEffect.h"
363 #include "SkGr.h"
365 // Note that this will return -1 if either matrix is perspective.
366 static SkScalar get_combined_min_stretch(const SkMatrix& viewMatrix, const SkMatrix& localMatrix) {
367 if (localMatrix.isIdentity()) {
368 return viewMatrix.getMinStretch();
369 } else {
370 SkMatrix combined;
371 combined.setConcat(viewMatrix, localMatrix);
372 return combined.getMinStretch();
373 }
374 }
376 GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
377 SkMatrix matrix;
378 matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
380 SkMatrix lmInverse;
381 if (!this->getLocalMatrix().invert(&lmInverse)) {
382 return NULL;
383 }
384 matrix.preConcat(lmInverse);
386 SkShader::TileMode tm[] = {
387 (TileMode)fState.fTileModeX,
388 (TileMode)fState.fTileModeY,
389 };
391 // Must set wrap and filter on the sampler before requesting a texture. In two places below
392 // we check the matrix scale factors to determine how to interpret the filter quality setting.
393 // This completely ignores the complexity of the drawVertices case where explicit local coords
394 // are provided by the caller.
395 SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel();
396 GrTextureParams::FilterMode textureFilterMode;
397 switch(paintFilterLevel) {
398 case SkPaint::kNone_FilterLevel:
399 textureFilterMode = GrTextureParams::kNone_FilterMode;
400 break;
401 case SkPaint::kLow_FilterLevel:
402 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
403 break;
404 case SkPaint::kMedium_FilterLevel:
405 if (get_combined_min_stretch(context->getMatrix(), this->getLocalMatrix()) <
406 SK_Scalar1) {
407 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
408 } else {
409 // Don't trigger MIP level generation unnecessarily.
410 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
411 }
412 break;
413 case SkPaint::kHigh_FilterLevel:
414 // Minification can look bad with bicubic filtering.
415 if (get_combined_min_stretch(context->getMatrix(), this->getLocalMatrix()) >=
416 SK_Scalar1) {
417 // fall back to no filtering here; we will install another shader that will do the
418 // HQ filtering.
419 textureFilterMode = GrTextureParams::kNone_FilterMode;
420 } else {
421 // Fall back to MIP-mapping.
422 paintFilterLevel = SkPaint::kMedium_FilterLevel;
423 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
424 }
425 break;
426 default:
427 SkErrorInternals::SetError( kInvalidPaint_SkError,
428 "Sorry, I don't understand the filtering "
429 "mode you asked for. Falling back to "
430 "MIPMaps.");
431 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
432 break;
434 }
435 GrTextureParams params(tm, textureFilterMode);
436 GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, fRawBitmap, ¶ms);
438 if (NULL == texture) {
439 SkErrorInternals::SetError( kInternalError_SkError,
440 "Couldn't convert bitmap to texture.");
441 return NULL;
442 }
444 GrEffectRef* effect = NULL;
445 if (paintFilterLevel == SkPaint::kHigh_FilterLevel) {
446 effect = GrBicubicEffect::Create(texture, matrix, tm);
447 } else {
448 effect = GrSimpleTextureEffect::Create(texture, matrix, params);
449 }
450 GrUnlockAndUnrefCachedBitmapTexture(texture);
451 return effect;
452 }
453 #endif