gfx/skia/trunk/src/core/SkBitmapProcState.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

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.

michael@0 1
michael@0 2 /*
michael@0 3 * Copyright 2011 Google Inc.
michael@0 4 *
michael@0 5 * Use of this source code is governed by a BSD-style license that can be
michael@0 6 * found in the LICENSE file.
michael@0 7 */
michael@0 8 #include "SkBitmapProcState.h"
michael@0 9 #include "SkColorPriv.h"
michael@0 10 #include "SkFilterProc.h"
michael@0 11 #include "SkPaint.h"
michael@0 12 #include "SkShader.h" // for tilemodes
michael@0 13 #include "SkUtilsArm.h"
michael@0 14 #include "SkBitmapScaler.h"
michael@0 15 #include "SkMipMap.h"
michael@0 16 #include "SkPixelRef.h"
michael@0 17 #include "SkScaledImageCache.h"
michael@0 18
michael@0 19 #if !SK_ARM_NEON_IS_NONE
michael@0 20 // These are defined in src/opts/SkBitmapProcState_arm_neon.cpp
michael@0 21 extern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[];
michael@0 22 extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[];
michael@0 23 extern void S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*);
michael@0 24 extern void Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
michael@0 25 extern void Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
michael@0 26 extern void SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*);
michael@0 27 extern void SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
michael@0 28 extern void Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
michael@0 29 #endif
michael@0 30
michael@0 31 #define NAME_WRAP(x) x
michael@0 32 #include "SkBitmapProcState_filter.h"
michael@0 33 #include "SkBitmapProcState_procs.h"
michael@0 34
michael@0 35 ///////////////////////////////////////////////////////////////////////////////
michael@0 36
michael@0 37 // true iff the matrix contains, at most, scale and translate elements
michael@0 38 static bool matrix_only_scale_translate(const SkMatrix& m) {
michael@0 39 return m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask);
michael@0 40 }
michael@0 41
michael@0 42 /**
michael@0 43 * For the purposes of drawing bitmaps, if a matrix is "almost" translate
michael@0 44 * go ahead and treat it as if it were, so that subsequent code can go fast.
michael@0 45 */
michael@0 46 static bool just_trans_clamp(const SkMatrix& matrix, const SkBitmap& bitmap) {
michael@0 47 SkASSERT(matrix_only_scale_translate(matrix));
michael@0 48
michael@0 49 if (matrix.getType() & SkMatrix::kScale_Mask) {
michael@0 50 SkRect src, dst;
michael@0 51 bitmap.getBounds(&src);
michael@0 52
michael@0 53 // Can't call mapRect(), since that will fix up inverted rectangles,
michael@0 54 // e.g. when scale is negative, and we don't want to return true for
michael@0 55 // those.
michael@0 56 matrix.mapPoints(SkTCast<SkPoint*>(&dst),
michael@0 57 SkTCast<const SkPoint*>(&src),
michael@0 58 2);
michael@0 59
michael@0 60 // Now round all 4 edges to device space, and then compare the device
michael@0 61 // width/height to the original. Note: we must map all 4 and subtract
michael@0 62 // rather than map the "width" and compare, since we care about the
michael@0 63 // phase (in pixel space) that any translate in the matrix might impart.
michael@0 64 SkIRect idst;
michael@0 65 dst.round(&idst);
michael@0 66 return idst.width() == bitmap.width() && idst.height() == bitmap.height();
michael@0 67 }
michael@0 68 // if we got here, we're either kTranslate_Mask or identity
michael@0 69 return true;
michael@0 70 }
michael@0 71
michael@0 72 static bool just_trans_general(const SkMatrix& matrix) {
michael@0 73 SkASSERT(matrix_only_scale_translate(matrix));
michael@0 74
michael@0 75 if (matrix.getType() & SkMatrix::kScale_Mask) {
michael@0 76 const SkScalar tol = SK_Scalar1 / 32768;
michael@0 77
michael@0 78 if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) {
michael@0 79 return false;
michael@0 80 }
michael@0 81 if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) {
michael@0 82 return false;
michael@0 83 }
michael@0 84 }
michael@0 85 // if we got here, treat us as either kTranslate_Mask or identity
michael@0 86 return true;
michael@0 87 }
michael@0 88
michael@0 89 ///////////////////////////////////////////////////////////////////////////////
michael@0 90
michael@0 91 static bool valid_for_filtering(unsigned dimension) {
michael@0 92 // for filtering, width and height must fit in 14bits, since we use steal
michael@0 93 // 2 bits from each to store our 4bit subpixel data
michael@0 94 return (dimension & ~0x3FFF) == 0;
michael@0 95 }
michael@0 96
michael@0 97 static SkScalar effective_matrix_scale_sqrd(const SkMatrix& mat) {
michael@0 98 SkPoint v1, v2;
michael@0 99
michael@0 100 v1.fX = mat.getScaleX();
michael@0 101 v1.fY = mat.getSkewY();
michael@0 102
michael@0 103 v2.fX = mat.getSkewX();
michael@0 104 v2.fY = mat.getScaleY();
michael@0 105
michael@0 106 return SkMaxScalar(v1.lengthSqd(), v2.lengthSqd());
michael@0 107 }
michael@0 108
michael@0 109 class AutoScaledCacheUnlocker {
michael@0 110 public:
michael@0 111 AutoScaledCacheUnlocker(SkScaledImageCache::ID** idPtr) : fIDPtr(idPtr) {}
michael@0 112 ~AutoScaledCacheUnlocker() {
michael@0 113 if (fIDPtr && *fIDPtr) {
michael@0 114 SkScaledImageCache::Unlock(*fIDPtr);
michael@0 115 *fIDPtr = NULL;
michael@0 116 }
michael@0 117 }
michael@0 118
michael@0 119 // forgets the ID, so it won't call Unlock
michael@0 120 void release() {
michael@0 121 fIDPtr = NULL;
michael@0 122 }
michael@0 123
michael@0 124 private:
michael@0 125 SkScaledImageCache::ID** fIDPtr;
michael@0 126 };
michael@0 127 #define AutoScaledCacheUnlocker(...) SK_REQUIRE_LOCAL_VAR(AutoScaledCacheUnlocker)
michael@0 128
michael@0 129 // TODO -- we may want to pass the clip into this function so we only scale
michael@0 130 // the portion of the image that we're going to need. This will complicate
michael@0 131 // the interface to the cache, but might be well worth it.
michael@0 132
michael@0 133 bool SkBitmapProcState::possiblyScaleImage() {
michael@0 134 AutoScaledCacheUnlocker unlocker(&fScaledCacheID);
michael@0 135
michael@0 136 SkASSERT(NULL == fBitmap);
michael@0 137 SkASSERT(NULL == fScaledCacheID);
michael@0 138
michael@0 139 if (fFilterLevel <= SkPaint::kLow_FilterLevel) {
michael@0 140 return false;
michael@0 141 }
michael@0 142
michael@0 143 // Check to see if the transformation matrix is simple, and if we're
michael@0 144 // doing high quality scaling. If so, do the bitmap scale here and
michael@0 145 // remove the scaling component from the matrix.
michael@0 146
michael@0 147 if (SkPaint::kHigh_FilterLevel == fFilterLevel &&
michael@0 148 fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask) &&
michael@0 149 fOrigBitmap.config() == SkBitmap::kARGB_8888_Config) {
michael@0 150
michael@0 151 SkScalar invScaleX = fInvMatrix.getScaleX();
michael@0 152 SkScalar invScaleY = fInvMatrix.getScaleY();
michael@0 153
michael@0 154 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap,
michael@0 155 invScaleX, invScaleY,
michael@0 156 &fScaledBitmap);
michael@0 157 if (fScaledCacheID) {
michael@0 158 fScaledBitmap.lockPixels();
michael@0 159 if (!fScaledBitmap.getPixels()) {
michael@0 160 fScaledBitmap.unlockPixels();
michael@0 161 // found a purged entry (discardablememory?), release it
michael@0 162 SkScaledImageCache::Unlock(fScaledCacheID);
michael@0 163 fScaledCacheID = NULL;
michael@0 164 // fall through to rebuild
michael@0 165 }
michael@0 166 }
michael@0 167
michael@0 168 if (NULL == fScaledCacheID) {
michael@0 169 int dest_width = SkScalarCeilToInt(fOrigBitmap.width() / invScaleX);
michael@0 170 int dest_height = SkScalarCeilToInt(fOrigBitmap.height() / invScaleY);
michael@0 171
michael@0 172 // All the criteria are met; let's make a new bitmap.
michael@0 173
michael@0 174 SkConvolutionProcs simd;
michael@0 175 sk_bzero(&simd, sizeof(simd));
michael@0 176 this->platformConvolutionProcs(&simd);
michael@0 177
michael@0 178 if (!SkBitmapScaler::Resize(&fScaledBitmap,
michael@0 179 fOrigBitmap,
michael@0 180 SkBitmapScaler::RESIZE_BEST,
michael@0 181 dest_width,
michael@0 182 dest_height,
michael@0 183 simd,
michael@0 184 SkScaledImageCache::GetAllocator())) {
michael@0 185 // we failed to create fScaledBitmap, so just return and let
michael@0 186 // the scanline proc handle it.
michael@0 187 return false;
michael@0 188
michael@0 189 }
michael@0 190 SkASSERT(NULL != fScaledBitmap.getPixels());
michael@0 191 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap,
michael@0 192 invScaleX,
michael@0 193 invScaleY,
michael@0 194 fScaledBitmap);
michael@0 195 if (!fScaledCacheID) {
michael@0 196 fScaledBitmap.reset();
michael@0 197 return false;
michael@0 198 }
michael@0 199 SkASSERT(NULL != fScaledBitmap.getPixels());
michael@0 200 }
michael@0 201
michael@0 202 SkASSERT(NULL != fScaledBitmap.getPixels());
michael@0 203 fBitmap = &fScaledBitmap;
michael@0 204
michael@0 205 // set the inv matrix type to translate-only;
michael@0 206 fInvMatrix.setTranslate(fInvMatrix.getTranslateX() / fInvMatrix.getScaleX(),
michael@0 207 fInvMatrix.getTranslateY() / fInvMatrix.getScaleY());
michael@0 208
michael@0 209 // no need for any further filtering; we just did it!
michael@0 210 fFilterLevel = SkPaint::kNone_FilterLevel;
michael@0 211 unlocker.release();
michael@0 212 return true;
michael@0 213 }
michael@0 214
michael@0 215 /*
michael@0 216 * If High, then our special-case for scale-only did not take, and so we
michael@0 217 * have to make a choice:
michael@0 218 * 1. fall back on mipmaps + bilerp
michael@0 219 * 2. fall back on scanline bicubic filter
michael@0 220 * For now, we compute the "scale" value from the matrix, and have a
michael@0 221 * threshold to decide when bicubic is better, and when mips are better.
michael@0 222 * No doubt a fancier decision tree could be used uere.
michael@0 223 *
michael@0 224 * If Medium, then we just try to build a mipmap and select a level,
michael@0 225 * setting the filter-level to kLow to signal that we just need bilerp
michael@0 226 * to process the selected level.
michael@0 227 */
michael@0 228
michael@0 229 SkScalar scaleSqd = effective_matrix_scale_sqrd(fInvMatrix);
michael@0 230
michael@0 231 if (SkPaint::kHigh_FilterLevel == fFilterLevel) {
michael@0 232 // Set the limit at 0.25 for the CTM... if the CTM is scaling smaller
michael@0 233 // than this, then the mipmaps quality may be greater (certainly faster)
michael@0 234 // so we only keep High quality if the scale is greater than this.
michael@0 235 //
michael@0 236 // Since we're dealing with the inverse, we compare against its inverse.
michael@0 237 const SkScalar bicubicLimit = 4.0f;
michael@0 238 const SkScalar bicubicLimitSqd = bicubicLimit * bicubicLimit;
michael@0 239 if (scaleSqd < bicubicLimitSqd) { // use bicubic scanline
michael@0 240 return false;
michael@0 241 }
michael@0 242
michael@0 243 // else set the filter-level to Medium, since we're scaling down and
michael@0 244 // want to reqeust mipmaps
michael@0 245 fFilterLevel = SkPaint::kMedium_FilterLevel;
michael@0 246 }
michael@0 247
michael@0 248 SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel);
michael@0 249
michael@0 250 /**
michael@0 251 * Medium quality means use a mipmap for down-scaling, and just bilper
michael@0 252 * for upscaling. Since we're examining the inverse matrix, we look for
michael@0 253 * a scale > 1 to indicate down scaling by the CTM.
michael@0 254 */
michael@0 255 if (scaleSqd > SK_Scalar1) {
michael@0 256 const SkMipMap* mip = NULL;
michael@0 257
michael@0 258 SkASSERT(NULL == fScaledCacheID);
michael@0 259 fScaledCacheID = SkScaledImageCache::FindAndLockMip(fOrigBitmap, &mip);
michael@0 260 if (!fScaledCacheID) {
michael@0 261 SkASSERT(NULL == mip);
michael@0 262 mip = SkMipMap::Build(fOrigBitmap);
michael@0 263 if (mip) {
michael@0 264 fScaledCacheID = SkScaledImageCache::AddAndLockMip(fOrigBitmap,
michael@0 265 mip);
michael@0 266 mip->unref(); // the cache took a ref
michael@0 267 SkASSERT(fScaledCacheID);
michael@0 268 }
michael@0 269 } else {
michael@0 270 SkASSERT(mip);
michael@0 271 }
michael@0 272
michael@0 273 if (mip) {
michael@0 274 SkScalar levelScale = SkScalarInvert(SkScalarSqrt(scaleSqd));
michael@0 275 SkMipMap::Level level;
michael@0 276 if (mip->extractLevel(levelScale, &level)) {
michael@0 277 SkScalar invScaleFixup = level.fScale;
michael@0 278 fInvMatrix.postScale(invScaleFixup, invScaleFixup);
michael@0 279
michael@0 280 fScaledBitmap.setConfig(fOrigBitmap.config(),
michael@0 281 level.fWidth, level.fHeight,
michael@0 282 level.fRowBytes);
michael@0 283 fScaledBitmap.setPixels(level.fPixels);
michael@0 284 fBitmap = &fScaledBitmap;
michael@0 285 fFilterLevel = SkPaint::kLow_FilterLevel;
michael@0 286 unlocker.release();
michael@0 287 return true;
michael@0 288 }
michael@0 289 }
michael@0 290 }
michael@0 291
michael@0 292 return false;
michael@0 293 }
michael@0 294
michael@0 295 static bool get_locked_pixels(const SkBitmap& src, int pow2, SkBitmap* dst) {
michael@0 296 SkPixelRef* pr = src.pixelRef();
michael@0 297 if (pr && pr->decodeInto(pow2, dst)) {
michael@0 298 return true;
michael@0 299 }
michael@0 300
michael@0 301 /*
michael@0 302 * If decodeInto() fails, it is possibe that we have an old subclass that
michael@0 303 * does not, or cannot, implement that. In that case we fall back to the
michael@0 304 * older protocol of having the pixelRef handle the caching for us.
michael@0 305 */
michael@0 306 *dst = src;
michael@0 307 dst->lockPixels();
michael@0 308 return SkToBool(dst->getPixels());
michael@0 309 }
michael@0 310
michael@0 311 bool SkBitmapProcState::lockBaseBitmap() {
michael@0 312 AutoScaledCacheUnlocker unlocker(&fScaledCacheID);
michael@0 313
michael@0 314 SkPixelRef* pr = fOrigBitmap.pixelRef();
michael@0 315
michael@0 316 SkASSERT(NULL == fScaledCacheID);
michael@0 317
michael@0 318 if (pr->isLocked() || !pr->implementsDecodeInto()) {
michael@0 319 // fast-case, no need to look in our cache
michael@0 320 fScaledBitmap = fOrigBitmap;
michael@0 321 fScaledBitmap.lockPixels();
michael@0 322 if (NULL == fScaledBitmap.getPixels()) {
michael@0 323 return false;
michael@0 324 }
michael@0 325 } else {
michael@0 326 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap,
michael@0 327 SK_Scalar1, SK_Scalar1,
michael@0 328 &fScaledBitmap);
michael@0 329 if (fScaledCacheID) {
michael@0 330 fScaledBitmap.lockPixels();
michael@0 331 if (!fScaledBitmap.getPixels()) {
michael@0 332 fScaledBitmap.unlockPixels();
michael@0 333 // found a purged entry (discardablememory?), release it
michael@0 334 SkScaledImageCache::Unlock(fScaledCacheID);
michael@0 335 fScaledCacheID = NULL;
michael@0 336 // fall through to rebuild
michael@0 337 }
michael@0 338 }
michael@0 339
michael@0 340 if (NULL == fScaledCacheID) {
michael@0 341 if (!get_locked_pixels(fOrigBitmap, 0, &fScaledBitmap)) {
michael@0 342 return false;
michael@0 343 }
michael@0 344
michael@0 345 // TODO: if fScaled comes back at a different width/height than fOrig,
michael@0 346 // we need to update the matrix we are using to sample from this guy.
michael@0 347
michael@0 348 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap,
michael@0 349 SK_Scalar1, SK_Scalar1,
michael@0 350 fScaledBitmap);
michael@0 351 if (!fScaledCacheID) {
michael@0 352 fScaledBitmap.reset();
michael@0 353 return false;
michael@0 354 }
michael@0 355 }
michael@0 356 }
michael@0 357 fBitmap = &fScaledBitmap;
michael@0 358 unlocker.release();
michael@0 359 return true;
michael@0 360 }
michael@0 361
michael@0 362 void SkBitmapProcState::endContext() {
michael@0 363 SkDELETE(fBitmapFilter);
michael@0 364 fBitmapFilter = NULL;
michael@0 365 fScaledBitmap.reset();
michael@0 366
michael@0 367 if (fScaledCacheID) {
michael@0 368 SkScaledImageCache::Unlock(fScaledCacheID);
michael@0 369 fScaledCacheID = NULL;
michael@0 370 }
michael@0 371 }
michael@0 372
michael@0 373 SkBitmapProcState::~SkBitmapProcState() {
michael@0 374 if (fScaledCacheID) {
michael@0 375 SkScaledImageCache::Unlock(fScaledCacheID);
michael@0 376 }
michael@0 377 SkDELETE(fBitmapFilter);
michael@0 378 }
michael@0 379
michael@0 380 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
michael@0 381 SkASSERT(fOrigBitmap.width() && fOrigBitmap.height());
michael@0 382
michael@0 383 fBitmap = NULL;
michael@0 384 fInvMatrix = inv;
michael@0 385 fFilterLevel = paint.getFilterLevel();
michael@0 386
michael@0 387 SkASSERT(NULL == fScaledCacheID);
michael@0 388
michael@0 389 // possiblyScaleImage will look to see if it can rescale the image as a
michael@0 390 // preprocess; either by scaling up to the target size, or by selecting
michael@0 391 // a nearby mipmap level. If it does, it will adjust the working
michael@0 392 // matrix as well as the working bitmap. It may also adjust the filter
michael@0 393 // quality to avoid re-filtering an already perfectly scaled image.
michael@0 394 if (!this->possiblyScaleImage()) {
michael@0 395 if (!this->lockBaseBitmap()) {
michael@0 396 return false;
michael@0 397 }
michael@0 398 }
michael@0 399 // The above logic should have always assigned fBitmap, but in case it
michael@0 400 // didn't, we check for that now...
michael@0 401 if (NULL == fBitmap) {
michael@0 402 return false;
michael@0 403 }
michael@0 404
michael@0 405 bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
michael@0 406 bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
michael@0 407 SkShader::kClamp_TileMode == fTileModeY;
michael@0 408
michael@0 409 if (!(clampClamp || trivialMatrix)) {
michael@0 410 fInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
michael@0 411 }
michael@0 412
michael@0 413 // Now that all possible changes to the matrix have taken place, check
michael@0 414 // to see if we're really close to a no-scale matrix. If so, explicitly
michael@0 415 // set it to be so. Subsequent code may inspect this matrix to choose
michael@0 416 // a faster path in this case.
michael@0 417
michael@0 418 // This code will only execute if the matrix has some scale component;
michael@0 419 // if it's already pure translate then we won't do this inversion.
michael@0 420
michael@0 421 if (matrix_only_scale_translate(fInvMatrix)) {
michael@0 422 SkMatrix forward;
michael@0 423 if (fInvMatrix.invert(&forward)) {
michael@0 424 if (clampClamp ? just_trans_clamp(forward, *fBitmap)
michael@0 425 : just_trans_general(forward)) {
michael@0 426 SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX());
michael@0 427 SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY());
michael@0 428 fInvMatrix.setTranslate(tx, ty);
michael@0 429 }
michael@0 430 }
michael@0 431 }
michael@0 432
michael@0 433 fInvProc = fInvMatrix.getMapXYProc();
michael@0 434 fInvType = fInvMatrix.getType();
michael@0 435 fInvSx = SkScalarToFixed(fInvMatrix.getScaleX());
michael@0 436 fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX());
michael@0 437 fInvKy = SkScalarToFixed(fInvMatrix.getSkewY());
michael@0 438 fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY());
michael@0 439
michael@0 440 fAlphaScale = SkAlpha255To256(paint.getAlpha());
michael@0 441
michael@0 442 fShaderProc32 = NULL;
michael@0 443 fShaderProc16 = NULL;
michael@0 444 fSampleProc32 = NULL;
michael@0 445 fSampleProc16 = NULL;
michael@0 446
michael@0 447 // recompute the triviality of the matrix here because we may have
michael@0 448 // changed it!
michael@0 449
michael@0 450 trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
michael@0 451
michael@0 452 if (SkPaint::kHigh_FilterLevel == fFilterLevel) {
michael@0 453 // If this is still set, that means we wanted HQ sampling
michael@0 454 // but couldn't do it as a preprocess. Let's try to install
michael@0 455 // the scanline version of the HQ sampler. If that process fails,
michael@0 456 // downgrade to bilerp.
michael@0 457
michael@0 458 // NOTE: Might need to be careful here in the future when we want
michael@0 459 // to have the platform proc have a shot at this; it's possible that
michael@0 460 // the chooseBitmapFilterProc will fail to install a shader but a
michael@0 461 // platform-specific one might succeed, so it might be premature here
michael@0 462 // to fall back to bilerp. This needs thought.
michael@0 463
michael@0 464 if (!this->setBitmapFilterProcs()) {
michael@0 465 fFilterLevel = SkPaint::kLow_FilterLevel;
michael@0 466 }
michael@0 467 }
michael@0 468
michael@0 469 if (SkPaint::kLow_FilterLevel == fFilterLevel) {
michael@0 470 // Only try bilerp if the matrix is "interesting" and
michael@0 471 // the image has a suitable size.
michael@0 472
michael@0 473 if (fInvType <= SkMatrix::kTranslate_Mask ||
michael@0 474 !valid_for_filtering(fBitmap->width() | fBitmap->height())) {
michael@0 475 fFilterLevel = SkPaint::kNone_FilterLevel;
michael@0 476 }
michael@0 477 }
michael@0 478
michael@0 479 // At this point, we know exactly what kind of sampling the per-scanline
michael@0 480 // shader will perform.
michael@0 481
michael@0 482 fMatrixProc = this->chooseMatrixProc(trivialMatrix);
michael@0 483 if (NULL == fMatrixProc) {
michael@0 484 return false;
michael@0 485 }
michael@0 486
michael@0 487 ///////////////////////////////////////////////////////////////////////
michael@0 488
michael@0 489 // No need to do this if we're doing HQ sampling; if filter quality is
michael@0 490 // still set to HQ by the time we get here, then we must have installed
michael@0 491 // the shader procs above and can skip all this.
michael@0 492
michael@0 493 if (fFilterLevel < SkPaint::kHigh_FilterLevel) {
michael@0 494
michael@0 495 int index = 0;
michael@0 496 if (fAlphaScale < 256) { // note: this distinction is not used for D16
michael@0 497 index |= 1;
michael@0 498 }
michael@0 499 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
michael@0 500 index |= 2;
michael@0 501 }
michael@0 502 if (fFilterLevel > SkPaint::kNone_FilterLevel) {
michael@0 503 index |= 4;
michael@0 504 }
michael@0 505 // bits 3,4,5 encoding the source bitmap format
michael@0 506 switch (fBitmap->config()) {
michael@0 507 case SkBitmap::kARGB_8888_Config:
michael@0 508 index |= 0;
michael@0 509 break;
michael@0 510 case SkBitmap::kRGB_565_Config:
michael@0 511 index |= 8;
michael@0 512 break;
michael@0 513 case SkBitmap::kIndex8_Config:
michael@0 514 index |= 16;
michael@0 515 break;
michael@0 516 case SkBitmap::kARGB_4444_Config:
michael@0 517 index |= 24;
michael@0 518 break;
michael@0 519 case SkBitmap::kA8_Config:
michael@0 520 index |= 32;
michael@0 521 fPaintPMColor = SkPreMultiplyColor(paint.getColor());
michael@0 522 break;
michael@0 523 default:
michael@0 524 return false;
michael@0 525 }
michael@0 526
michael@0 527 #if !SK_ARM_NEON_IS_ALWAYS
michael@0 528 static const SampleProc32 gSkBitmapProcStateSample32[] = {
michael@0 529 S32_opaque_D32_nofilter_DXDY,
michael@0 530 S32_alpha_D32_nofilter_DXDY,
michael@0 531 S32_opaque_D32_nofilter_DX,
michael@0 532 S32_alpha_D32_nofilter_DX,
michael@0 533 S32_opaque_D32_filter_DXDY,
michael@0 534 S32_alpha_D32_filter_DXDY,
michael@0 535 S32_opaque_D32_filter_DX,
michael@0 536 S32_alpha_D32_filter_DX,
michael@0 537
michael@0 538 S16_opaque_D32_nofilter_DXDY,
michael@0 539 S16_alpha_D32_nofilter_DXDY,
michael@0 540 S16_opaque_D32_nofilter_DX,
michael@0 541 S16_alpha_D32_nofilter_DX,
michael@0 542 S16_opaque_D32_filter_DXDY,
michael@0 543 S16_alpha_D32_filter_DXDY,
michael@0 544 S16_opaque_D32_filter_DX,
michael@0 545 S16_alpha_D32_filter_DX,
michael@0 546
michael@0 547 SI8_opaque_D32_nofilter_DXDY,
michael@0 548 SI8_alpha_D32_nofilter_DXDY,
michael@0 549 SI8_opaque_D32_nofilter_DX,
michael@0 550 SI8_alpha_D32_nofilter_DX,
michael@0 551 SI8_opaque_D32_filter_DXDY,
michael@0 552 SI8_alpha_D32_filter_DXDY,
michael@0 553 SI8_opaque_D32_filter_DX,
michael@0 554 SI8_alpha_D32_filter_DX,
michael@0 555
michael@0 556 S4444_opaque_D32_nofilter_DXDY,
michael@0 557 S4444_alpha_D32_nofilter_DXDY,
michael@0 558 S4444_opaque_D32_nofilter_DX,
michael@0 559 S4444_alpha_D32_nofilter_DX,
michael@0 560 S4444_opaque_D32_filter_DXDY,
michael@0 561 S4444_alpha_D32_filter_DXDY,
michael@0 562 S4444_opaque_D32_filter_DX,
michael@0 563 S4444_alpha_D32_filter_DX,
michael@0 564
michael@0 565 // A8 treats alpha/opaque the same (equally efficient)
michael@0 566 SA8_alpha_D32_nofilter_DXDY,
michael@0 567 SA8_alpha_D32_nofilter_DXDY,
michael@0 568 SA8_alpha_D32_nofilter_DX,
michael@0 569 SA8_alpha_D32_nofilter_DX,
michael@0 570 SA8_alpha_D32_filter_DXDY,
michael@0 571 SA8_alpha_D32_filter_DXDY,
michael@0 572 SA8_alpha_D32_filter_DX,
michael@0 573 SA8_alpha_D32_filter_DX
michael@0 574 };
michael@0 575
michael@0 576 static const SampleProc16 gSkBitmapProcStateSample16[] = {
michael@0 577 S32_D16_nofilter_DXDY,
michael@0 578 S32_D16_nofilter_DX,
michael@0 579 S32_D16_filter_DXDY,
michael@0 580 S32_D16_filter_DX,
michael@0 581
michael@0 582 S16_D16_nofilter_DXDY,
michael@0 583 S16_D16_nofilter_DX,
michael@0 584 S16_D16_filter_DXDY,
michael@0 585 S16_D16_filter_DX,
michael@0 586
michael@0 587 SI8_D16_nofilter_DXDY,
michael@0 588 SI8_D16_nofilter_DX,
michael@0 589 SI8_D16_filter_DXDY,
michael@0 590 SI8_D16_filter_DX,
michael@0 591
michael@0 592 // Don't support 4444 -> 565
michael@0 593 NULL, NULL, NULL, NULL,
michael@0 594 // Don't support A8 -> 565
michael@0 595 NULL, NULL, NULL, NULL
michael@0 596 };
michael@0 597 #endif
michael@0 598
michael@0 599 fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index];
michael@0 600 index >>= 1; // shift away any opaque/alpha distinction
michael@0 601 fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index];
michael@0 602
michael@0 603 // our special-case shaderprocs
michael@0 604 if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) {
michael@0 605 if (clampClamp) {
michael@0 606 fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc);
michael@0 607 } else if (SkShader::kRepeat_TileMode == fTileModeX &&
michael@0 608 SkShader::kRepeat_TileMode == fTileModeY) {
michael@0 609 fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc);
michael@0 610 }
michael@0 611 } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clampClamp) {
michael@0 612 fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc);
michael@0 613 }
michael@0 614
michael@0 615 if (NULL == fShaderProc32) {
michael@0 616 fShaderProc32 = this->chooseShaderProc32();
michael@0 617 }
michael@0 618 }
michael@0 619
michael@0 620 // see if our platform has any accelerated overrides
michael@0 621 this->platformProcs();
michael@0 622
michael@0 623 return true;
michael@0 624 }
michael@0 625
michael@0 626 static void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
michael@0 627 int x, int y,
michael@0 628 SkPMColor* SK_RESTRICT colors,
michael@0 629 int count) {
michael@0 630 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
michael@0 631 SkASSERT(s.fInvKy == 0);
michael@0 632 SkASSERT(count > 0 && colors != NULL);
michael@0 633 SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel);
michael@0 634
michael@0 635 const int maxX = s.fBitmap->width() - 1;
michael@0 636 const int maxY = s.fBitmap->height() - 1;
michael@0 637 int ix = s.fFilterOneX + x;
michael@0 638 int iy = SkClampMax(s.fFilterOneY + y, maxY);
michael@0 639 #ifdef SK_DEBUG
michael@0 640 {
michael@0 641 SkPoint pt;
michael@0 642 s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
michael@0 643 SkIntToScalar(y) + SK_ScalarHalf, &pt);
michael@0 644 int iy2 = SkClampMax(SkScalarFloorToInt(pt.fY), maxY);
michael@0 645 int ix2 = SkScalarFloorToInt(pt.fX);
michael@0 646
michael@0 647 SkASSERT(iy == iy2);
michael@0 648 SkASSERT(ix == ix2);
michael@0 649 }
michael@0 650 #endif
michael@0 651 const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
michael@0 652
michael@0 653 // clamp to the left
michael@0 654 if (ix < 0) {
michael@0 655 int n = SkMin32(-ix, count);
michael@0 656 sk_memset32(colors, row[0], n);
michael@0 657 count -= n;
michael@0 658 if (0 == count) {
michael@0 659 return;
michael@0 660 }
michael@0 661 colors += n;
michael@0 662 SkASSERT(-ix == n);
michael@0 663 ix = 0;
michael@0 664 }
michael@0 665 // copy the middle
michael@0 666 if (ix <= maxX) {
michael@0 667 int n = SkMin32(maxX - ix + 1, count);
michael@0 668 memcpy(colors, row + ix, n * sizeof(SkPMColor));
michael@0 669 count -= n;
michael@0 670 if (0 == count) {
michael@0 671 return;
michael@0 672 }
michael@0 673 colors += n;
michael@0 674 }
michael@0 675 SkASSERT(count > 0);
michael@0 676 // clamp to the right
michael@0 677 sk_memset32(colors, row[maxX], count);
michael@0 678 }
michael@0 679
michael@0 680 static inline int sk_int_mod(int x, int n) {
michael@0 681 SkASSERT(n > 0);
michael@0 682 if ((unsigned)x >= (unsigned)n) {
michael@0 683 if (x < 0) {
michael@0 684 x = n + ~(~x % n);
michael@0 685 } else {
michael@0 686 x = x % n;
michael@0 687 }
michael@0 688 }
michael@0 689 return x;
michael@0 690 }
michael@0 691
michael@0 692 static inline int sk_int_mirror(int x, int n) {
michael@0 693 x = sk_int_mod(x, 2 * n);
michael@0 694 if (x >= n) {
michael@0 695 x = n + ~(x - n);
michael@0 696 }
michael@0 697 return x;
michael@0 698 }
michael@0 699
michael@0 700 static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
michael@0 701 int x, int y,
michael@0 702 SkPMColor* SK_RESTRICT colors,
michael@0 703 int count) {
michael@0 704 SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
michael@0 705 SkASSERT(s.fInvKy == 0);
michael@0 706 SkASSERT(count > 0 && colors != NULL);
michael@0 707 SkASSERT(SkPaint::kNone_FilterLevel == s.fFilterLevel);
michael@0 708
michael@0 709 const int stopX = s.fBitmap->width();
michael@0 710 const int stopY = s.fBitmap->height();
michael@0 711 int ix = s.fFilterOneX + x;
michael@0 712 int iy = sk_int_mod(s.fFilterOneY + y, stopY);
michael@0 713 #ifdef SK_DEBUG
michael@0 714 {
michael@0 715 SkPoint pt;
michael@0 716 s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
michael@0 717 SkIntToScalar(y) + SK_ScalarHalf, &pt);
michael@0 718 int iy2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
michael@0 719 int ix2 = SkScalarFloorToInt(pt.fX);
michael@0 720
michael@0 721 SkASSERT(iy == iy2);
michael@0 722 SkASSERT(ix == ix2);
michael@0 723 }
michael@0 724 #endif
michael@0 725 const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
michael@0 726
michael@0 727 ix = sk_int_mod(ix, stopX);
michael@0 728 for (;;) {
michael@0 729 int n = SkMin32(stopX - ix, count);
michael@0 730 memcpy(colors, row + ix, n * sizeof(SkPMColor));
michael@0 731 count -= n;
michael@0 732 if (0 == count) {
michael@0 733 return;
michael@0 734 }
michael@0 735 colors += n;
michael@0 736 ix = 0;
michael@0 737 }
michael@0 738 }
michael@0 739
michael@0 740 static void S32_D32_constX_shaderproc(const SkBitmapProcState& s,
michael@0 741 int x, int y,
michael@0 742 SkPMColor* SK_RESTRICT colors,
michael@0 743 int count) {
michael@0 744 SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0);
michael@0 745 SkASSERT(s.fInvKy == 0);
michael@0 746 SkASSERT(count > 0 && colors != NULL);
michael@0 747 SkASSERT(1 == s.fBitmap->width());
michael@0 748
michael@0 749 int iY0;
michael@0 750 int iY1 SK_INIT_TO_AVOID_WARNING;
michael@0 751 int iSubY SK_INIT_TO_AVOID_WARNING;
michael@0 752
michael@0 753 if (SkPaint::kNone_FilterLevel != s.fFilterLevel) {
michael@0 754 SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
michael@0 755 uint32_t xy[2];
michael@0 756
michael@0 757 mproc(s, xy, 1, x, y);
michael@0 758
michael@0 759 iY0 = xy[0] >> 18;
michael@0 760 iY1 = xy[0] & 0x3FFF;
michael@0 761 iSubY = (xy[0] >> 14) & 0xF;
michael@0 762 } else {
michael@0 763 int yTemp;
michael@0 764
michael@0 765 if (s.fInvType > SkMatrix::kTranslate_Mask) {
michael@0 766 SkPoint pt;
michael@0 767 s.fInvProc(s.fInvMatrix,
michael@0 768 SkIntToScalar(x) + SK_ScalarHalf,
michael@0 769 SkIntToScalar(y) + SK_ScalarHalf,
michael@0 770 &pt);
michael@0 771 // When the matrix has a scale component the setup code in
michael@0 772 // chooseProcs multiples the inverse matrix by the inverse of the
michael@0 773 // bitmap's width and height. Since this method is going to do
michael@0 774 // its own tiling and sampling we need to undo that here.
michael@0 775 if (SkShader::kClamp_TileMode != s.fTileModeX ||
michael@0 776 SkShader::kClamp_TileMode != s.fTileModeY) {
michael@0 777 yTemp = SkScalarFloorToInt(pt.fY * s.fBitmap->height());
michael@0 778 } else {
michael@0 779 yTemp = SkScalarFloorToInt(pt.fY);
michael@0 780 }
michael@0 781 } else {
michael@0 782 yTemp = s.fFilterOneY + y;
michael@0 783 }
michael@0 784
michael@0 785 const int stopY = s.fBitmap->height();
michael@0 786 switch (s.fTileModeY) {
michael@0 787 case SkShader::kClamp_TileMode:
michael@0 788 iY0 = SkClampMax(yTemp, stopY-1);
michael@0 789 break;
michael@0 790 case SkShader::kRepeat_TileMode:
michael@0 791 iY0 = sk_int_mod(yTemp, stopY);
michael@0 792 break;
michael@0 793 case SkShader::kMirror_TileMode:
michael@0 794 default:
michael@0 795 iY0 = sk_int_mirror(yTemp, stopY);
michael@0 796 break;
michael@0 797 }
michael@0 798
michael@0 799 #ifdef SK_DEBUG
michael@0 800 {
michael@0 801 SkPoint pt;
michael@0 802 s.fInvProc(s.fInvMatrix,
michael@0 803 SkIntToScalar(x) + SK_ScalarHalf,
michael@0 804 SkIntToScalar(y) + SK_ScalarHalf,
michael@0 805 &pt);
michael@0 806 if (s.fInvType > SkMatrix::kTranslate_Mask &&
michael@0 807 (SkShader::kClamp_TileMode != s.fTileModeX ||
michael@0 808 SkShader::kClamp_TileMode != s.fTileModeY)) {
michael@0 809 pt.fY *= s.fBitmap->height();
michael@0 810 }
michael@0 811 int iY2;
michael@0 812
michael@0 813 switch (s.fTileModeY) {
michael@0 814 case SkShader::kClamp_TileMode:
michael@0 815 iY2 = SkClampMax(SkScalarFloorToInt(pt.fY), stopY-1);
michael@0 816 break;
michael@0 817 case SkShader::kRepeat_TileMode:
michael@0 818 iY2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
michael@0 819 break;
michael@0 820 case SkShader::kMirror_TileMode:
michael@0 821 default:
michael@0 822 iY2 = sk_int_mirror(SkScalarFloorToInt(pt.fY), stopY);
michael@0 823 break;
michael@0 824 }
michael@0 825
michael@0 826 SkASSERT(iY0 == iY2);
michael@0 827 }
michael@0 828 #endif
michael@0 829 }
michael@0 830
michael@0 831 const SkPMColor* row0 = s.fBitmap->getAddr32(0, iY0);
michael@0 832 SkPMColor color;
michael@0 833
michael@0 834 if (SkPaint::kNone_FilterLevel != s.fFilterLevel) {
michael@0 835 const SkPMColor* row1 = s.fBitmap->getAddr32(0, iY1);
michael@0 836
michael@0 837 if (s.fAlphaScale < 256) {
michael@0 838 Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale);
michael@0 839 } else {
michael@0 840 Filter_32_opaque(iSubY, *row0, *row1, &color);
michael@0 841 }
michael@0 842 } else {
michael@0 843 if (s.fAlphaScale < 256) {
michael@0 844 color = SkAlphaMulQ(*row0, s.fAlphaScale);
michael@0 845 } else {
michael@0 846 color = *row0;
michael@0 847 }
michael@0 848 }
michael@0 849
michael@0 850 sk_memset32(colors, color, count);
michael@0 851 }
michael@0 852
michael@0 853 static void DoNothing_shaderproc(const SkBitmapProcState&, int x, int y,
michael@0 854 SkPMColor* SK_RESTRICT colors, int count) {
michael@0 855 // if we get called, the matrix is too tricky, so we just draw nothing
michael@0 856 sk_memset32(colors, 0, count);
michael@0 857 }
michael@0 858
michael@0 859 bool SkBitmapProcState::setupForTranslate() {
michael@0 860 SkPoint pt;
michael@0 861 fInvProc(fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt);
michael@0 862
michael@0 863 /*
michael@0 864 * if the translate is larger than our ints, we can get random results, or
michael@0 865 * worse, we might get 0x80000000, which wreaks havoc on us, since we can't
michael@0 866 * negate it.
michael@0 867 */
michael@0 868 const SkScalar too_big = SkIntToScalar(1 << 30);
michael@0 869 if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) {
michael@0 870 return false;
michael@0 871 }
michael@0 872
michael@0 873 // Since we know we're not filtered, we re-purpose these fields allow
michael@0 874 // us to go from device -> src coordinates w/ just an integer add,
michael@0 875 // rather than running through the inverse-matrix
michael@0 876 fFilterOneX = SkScalarFloorToInt(pt.fX);
michael@0 877 fFilterOneY = SkScalarFloorToInt(pt.fY);
michael@0 878 return true;
michael@0 879 }
michael@0 880
michael@0 881 SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
michael@0 882
michael@0 883 if (SkBitmap::kARGB_8888_Config != fBitmap->config()) {
michael@0 884 return NULL;
michael@0 885 }
michael@0 886
michael@0 887 static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
michael@0 888
michael@0 889 if (1 == fBitmap->width() && 0 == (fInvType & ~kMask)) {
michael@0 890 if (SkPaint::kNone_FilterLevel == fFilterLevel &&
michael@0 891 fInvType <= SkMatrix::kTranslate_Mask &&
michael@0 892 !this->setupForTranslate()) {
michael@0 893 return DoNothing_shaderproc;
michael@0 894 }
michael@0 895 return S32_D32_constX_shaderproc;
michael@0 896 }
michael@0 897
michael@0 898 if (fAlphaScale < 256) {
michael@0 899 return NULL;
michael@0 900 }
michael@0 901 if (fInvType > SkMatrix::kTranslate_Mask) {
michael@0 902 return NULL;
michael@0 903 }
michael@0 904 if (SkPaint::kNone_FilterLevel != fFilterLevel) {
michael@0 905 return NULL;
michael@0 906 }
michael@0 907
michael@0 908 SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
michael@0 909 SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
michael@0 910
michael@0 911 if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) {
michael@0 912 if (this->setupForTranslate()) {
michael@0 913 return Clamp_S32_D32_nofilter_trans_shaderproc;
michael@0 914 }
michael@0 915 return DoNothing_shaderproc;
michael@0 916 }
michael@0 917 if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) {
michael@0 918 if (this->setupForTranslate()) {
michael@0 919 return Repeat_S32_D32_nofilter_trans_shaderproc;
michael@0 920 }
michael@0 921 return DoNothing_shaderproc;
michael@0 922 }
michael@0 923 return NULL;
michael@0 924 }
michael@0 925
michael@0 926 ///////////////////////////////////////////////////////////////////////////////
michael@0 927
michael@0 928 #ifdef SK_DEBUG
michael@0 929
michael@0 930 static void check_scale_nofilter(uint32_t bitmapXY[], int count,
michael@0 931 unsigned mx, unsigned my) {
michael@0 932 unsigned y = *bitmapXY++;
michael@0 933 SkASSERT(y < my);
michael@0 934
michael@0 935 const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY);
michael@0 936 for (int i = 0; i < count; ++i) {
michael@0 937 SkASSERT(xptr[i] < mx);
michael@0 938 }
michael@0 939 }
michael@0 940
michael@0 941 static void check_scale_filter(uint32_t bitmapXY[], int count,
michael@0 942 unsigned mx, unsigned my) {
michael@0 943 uint32_t YY = *bitmapXY++;
michael@0 944 unsigned y0 = YY >> 18;
michael@0 945 unsigned y1 = YY & 0x3FFF;
michael@0 946 SkASSERT(y0 < my);
michael@0 947 SkASSERT(y1 < my);
michael@0 948
michael@0 949 for (int i = 0; i < count; ++i) {
michael@0 950 uint32_t XX = bitmapXY[i];
michael@0 951 unsigned x0 = XX >> 18;
michael@0 952 unsigned x1 = XX & 0x3FFF;
michael@0 953 SkASSERT(x0 < mx);
michael@0 954 SkASSERT(x1 < mx);
michael@0 955 }
michael@0 956 }
michael@0 957
michael@0 958 static void check_affine_nofilter(uint32_t bitmapXY[], int count,
michael@0 959 unsigned mx, unsigned my) {
michael@0 960 for (int i = 0; i < count; ++i) {
michael@0 961 uint32_t XY = bitmapXY[i];
michael@0 962 unsigned x = XY & 0xFFFF;
michael@0 963 unsigned y = XY >> 16;
michael@0 964 SkASSERT(x < mx);
michael@0 965 SkASSERT(y < my);
michael@0 966 }
michael@0 967 }
michael@0 968
michael@0 969 static void check_affine_filter(uint32_t bitmapXY[], int count,
michael@0 970 unsigned mx, unsigned my) {
michael@0 971 for (int i = 0; i < count; ++i) {
michael@0 972 uint32_t YY = *bitmapXY++;
michael@0 973 unsigned y0 = YY >> 18;
michael@0 974 unsigned y1 = YY & 0x3FFF;
michael@0 975 SkASSERT(y0 < my);
michael@0 976 SkASSERT(y1 < my);
michael@0 977
michael@0 978 uint32_t XX = *bitmapXY++;
michael@0 979 unsigned x0 = XX >> 18;
michael@0 980 unsigned x1 = XX & 0x3FFF;
michael@0 981 SkASSERT(x0 < mx);
michael@0 982 SkASSERT(x1 < mx);
michael@0 983 }
michael@0 984 }
michael@0 985
michael@0 986 void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
michael@0 987 uint32_t bitmapXY[], int count,
michael@0 988 int x, int y) {
michael@0 989 SkASSERT(bitmapXY);
michael@0 990 SkASSERT(count > 0);
michael@0 991
michael@0 992 state.fMatrixProc(state, bitmapXY, count, x, y);
michael@0 993
michael@0 994 void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my);
michael@0 995
michael@0 996 // There are four formats possible:
michael@0 997 // scale -vs- affine
michael@0 998 // filter -vs- nofilter
michael@0 999 if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
michael@0 1000 proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_scale_filter : check_scale_nofilter;
michael@0 1001 } else {
michael@0 1002 proc = state.fFilterLevel != SkPaint::kNone_FilterLevel ? check_affine_filter : check_affine_nofilter;
michael@0 1003 }
michael@0 1004 proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height());
michael@0 1005 }
michael@0 1006
michael@0 1007 SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const {
michael@0 1008 return DebugMatrixProc;
michael@0 1009 }
michael@0 1010
michael@0 1011 #endif
michael@0 1012
michael@0 1013 ///////////////////////////////////////////////////////////////////////////////
michael@0 1014 /*
michael@0 1015 The storage requirements for the different matrix procs are as follows,
michael@0 1016 where each X or Y is 2 bytes, and N is the number of pixels/elements:
michael@0 1017
michael@0 1018 scale/translate nofilter Y(4bytes) + N * X
michael@0 1019 affine/perspective nofilter N * (X Y)
michael@0 1020 scale/translate filter Y Y + N * (X X)
michael@0 1021 affine/perspective filter N * (Y Y X X)
michael@0 1022 */
michael@0 1023 int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
michael@0 1024 int32_t size = static_cast<int32_t>(bufferSize);
michael@0 1025
michael@0 1026 size &= ~3; // only care about 4-byte aligned chunks
michael@0 1027 if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
michael@0 1028 size -= 4; // the shared Y (or YY) coordinate
michael@0 1029 if (size < 0) {
michael@0 1030 size = 0;
michael@0 1031 }
michael@0 1032 size >>= 1;
michael@0 1033 } else {
michael@0 1034 size >>= 2;
michael@0 1035 }
michael@0 1036
michael@0 1037 if (fFilterLevel != SkPaint::kNone_FilterLevel) {
michael@0 1038 size >>= 1;
michael@0 1039 }
michael@0 1040
michael@0 1041 return size;
michael@0 1042 }

mercurial