Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(115)

Side by Side Diff: Source/core/platform/graphics/skia/NativeImageSkia.cpp

Issue 99103006: Moving GraphicsContext and dependencies from core to platform. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Final patch - fixes Android Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2008, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "core/platform/graphics/skia/NativeImageSkia.h"
33
34 #include "core/platform/graphics/GraphicsContext.h"
35 #include "core/platform/graphics/Image.h"
36 #include "core/platform/graphics/DeferredImageDecoder.h"
37 #include "core/platform/graphics/skia/SkiaUtils.h"
38 #include "platform/PlatformInstrumentation.h"
39 #include "platform/TraceEvent.h"
40 #include "platform/geometry/FloatPoint.h"
41 #include "platform/geometry/FloatRect.h"
42 #include "platform/geometry/FloatSize.h"
43 #include "skia/ext/image_operations.h"
44 #include "third_party/skia/include/core/SkMatrix.h"
45 #include "third_party/skia/include/core/SkPaint.h"
46 #include "third_party/skia/include/core/SkScalar.h"
47 #include "third_party/skia/include/core/SkShader.h"
48
49 #include <math.h>
50 #include <limits>
51
52 namespace WebCore {
53
54 static bool nearlyIntegral(float value)
55 {
56 return fabs(value - floorf(value)) < std::numeric_limits<float>::epsilon();
57 }
58
59 ResamplingMode NativeImageSkia::computeResamplingMode(const SkMatrix& matrix, fl oat srcWidth, float srcHeight, float destWidth, float destHeight) const
60 {
61 // The percent change below which we will not resample. This usually means
62 // an off-by-one error on the web page, and just doing nearest neighbor
63 // sampling is usually good enough.
64 const float kFractionalChangeThreshold = 0.025f;
65
66 // Images smaller than this in either direction are considered "small" and
67 // are not resampled ever (see below).
68 const int kSmallImageSizeThreshold = 8;
69
70 // The amount an image can be stretched in a single direction before we
71 // say that it is being stretched so much that it must be a line or
72 // background that doesn't need resampling.
73 const float kLargeStretch = 3.0f;
74
75 // Figure out if we should resample this image. We try to prune out some
76 // common cases where resampling won't give us anything, since it is much
77 // slower than drawing stretched.
78 float diffWidth = fabs(destWidth - srcWidth);
79 float diffHeight = fabs(destHeight - srcHeight);
80 bool widthNearlyEqual = diffWidth < std::numeric_limits<float>::epsilon();
81 bool heightNearlyEqual = diffHeight < std::numeric_limits<float>::epsilon();
82 // We don't need to resample if the source and destination are the same.
83 if (widthNearlyEqual && heightNearlyEqual)
84 return NoResampling;
85
86 if (srcWidth <= kSmallImageSizeThreshold
87 || srcHeight <= kSmallImageSizeThreshold
88 || destWidth <= kSmallImageSizeThreshold
89 || destHeight <= kSmallImageSizeThreshold) {
90 // Small image detected.
91
92 // Resample in the case where the new size would be non-integral.
93 // This can cause noticeable breaks in repeating patterns, except
94 // when the source image is only one pixel wide in that dimension.
95 if ((!nearlyIntegral(destWidth) && srcWidth > 1 + std::numeric_limits<fl oat>::epsilon())
96 || (!nearlyIntegral(destHeight) && srcHeight > 1 + std::numeric_limi ts<float>::epsilon()))
97 return LinearResampling;
98
99 // Otherwise, don't resample small images. These are often used for
100 // borders and rules (think 1x1 images used to make lines).
101 return NoResampling;
102 }
103
104 if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= d estWidth) {
105 // Large image detected.
106
107 // Don't resample if it is being stretched a lot in only one direction.
108 // This is trying to catch cases where somebody has created a border
109 // (which might be large) and then is stretching it to fill some part
110 // of the page.
111 if (widthNearlyEqual || heightNearlyEqual)
112 return NoResampling;
113
114 // The image is growing a lot and in more than one direction. Resampling
115 // is slow and doesn't give us very much when growing a lot.
116 return LinearResampling;
117 }
118
119 if ((diffWidth / srcWidth < kFractionalChangeThreshold)
120 && (diffHeight / srcHeight < kFractionalChangeThreshold)) {
121 // It is disappointingly common on the web for image sizes to be off by
122 // one or two pixels. We don't bother resampling if the size difference
123 // is a small fraction of the original size.
124 return NoResampling;
125 }
126
127 // When the image is not yet done loading, use linear. We don't cache the
128 // partially resampled images, and as they come in incrementally, it causes
129 // us to have to resample the whole thing every time.
130 if (!isDataComplete())
131 return LinearResampling;
132
133 // Everything else gets resampled.
134 // High quality interpolation only enabled for scaling and translation.
135 if (!(matrix.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Ma sk)))
136 return AwesomeResampling;
137
138 return LinearResampling;
139 }
140
141 static ResamplingMode limitResamplingMode(GraphicsContext* context, ResamplingMo de resampling)
142 {
143 switch (context->imageInterpolationQuality()) {
144 case InterpolationNone:
145 return NoResampling;
146 case InterpolationMedium:
147 // For now we treat InterpolationMedium and InterpolationLow the same.
148 case InterpolationLow:
149 if (resampling == AwesomeResampling)
150 return LinearResampling;
151 break;
152 case InterpolationHigh:
153 case InterpolationDefault:
154 break;
155 }
156
157 return resampling;
158 }
159
160 // This function is used to scale an image and extract a scaled fragment.
161 //
162 // ALGORITHM
163 //
164 // Because the scaled image size has to be integers, we approximate the real
165 // scale with the following formula (only X direction is shown):
166 //
167 // scaledImageWidth = round(scaleX * imageRect.width())
168 // approximateScaleX = scaledImageWidth / imageRect.width()
169 //
170 // With this method we maintain a constant scale factor among fragments in
171 // the scaled image. This allows fragments to stitch together to form the
172 // full scaled image. The downside is there will be a small difference
173 // between |scaleX| and |approximateScaleX|.
174 //
175 // A scaled image fragment is identified by:
176 //
177 // - Scaled image size
178 // - Scaled image fragment rectangle (IntRect)
179 //
180 // Scaled image size has been determined and the next step is to compute the
181 // rectangle for the scaled image fragment which needs to be an IntRect.
182 //
183 // scaledSrcRect = srcRect * (approximateScaleX, approximateScaleY)
184 // enclosingScaledSrcRect = enclosingIntRect(scaledSrcRect)
185 //
186 // Finally we extract the scaled image fragment using
187 // (scaledImageSize, enclosingScaledSrcRect).
188 //
189 SkBitmap NativeImageSkia::extractScaledImageFragment(const SkRect& srcRect, floa t scaleX, float scaleY, SkRect* scaledSrcRect) const
190 {
191 SkISize imageSize = SkISize::Make(bitmap().width(), bitmap().height());
192 SkISize scaledImageSize = SkISize::Make(clampToInteger(roundf(imageSize.widt h() * scaleX)),
193 clampToInteger(roundf(imageSize.height() * scaleY)));
194
195 SkRect imageRect = SkRect::MakeWH(imageSize.width(), imageSize.height());
196 SkRect scaledImageRect = SkRect::MakeWH(scaledImageSize.width(), scaledImage Size.height());
197
198 SkMatrix scaleTransform;
199 scaleTransform.setRectToRect(imageRect, scaledImageRect, SkMatrix::kFill_Sca leToFit);
200 scaleTransform.mapRect(scaledSrcRect, srcRect);
201
202 scaledSrcRect->intersect(scaledImageRect);
203 SkIRect enclosingScaledSrcRect = enclosingIntRect(*scaledSrcRect);
204
205 // |enclosingScaledSrcRect| can be larger than |scaledImageSize| because
206 // of float inaccuracy so clip to get inside.
207 enclosingScaledSrcRect.intersect(SkIRect::MakeSize(scaledImageSize));
208
209 // scaledSrcRect is relative to the pixel snapped fragment we're extracting.
210 scaledSrcRect->offset(-enclosingScaledSrcRect.x(), -enclosingScaledSrcRect.y ());
211
212 return resizedBitmap(scaledImageSize, enclosingScaledSrcRect);
213 }
214
215 // This does a lot of computation to resample only the portion of the bitmap
216 // that will only be drawn. This is critical for performance since when we are
217 // scrolling, for example, we are only drawing a small strip of the image.
218 // Resampling the whole image every time is very slow, so this speeds up things
219 // dramatically.
220 //
221 // Note: this code is only used when the canvas transformation is limited to
222 // scaling or translation.
223 void NativeImageSkia::drawResampledBitmap(GraphicsContext* context, SkPaint& pai nt, const SkRect& srcRect, const SkRect& destRect) const
224 {
225 TRACE_EVENT0("skia", "drawResampledBitmap");
226 // We want to scale |destRect| with transformation in the canvas to obtain
227 // the final scale. The final scale is a combination of scale transform
228 // in canvas and explicit scaling (srcRect and destRect).
229 SkRect screenRect;
230 context->getTotalMatrix().mapRect(&screenRect, destRect);
231 float realScaleX = screenRect.width() / srcRect.width();
232 float realScaleY = screenRect.height() / srcRect.height();
233
234 // This part of code limits scaling only to visible portion in the
235 SkRect destRectVisibleSubset;
236 ClipRectToCanvas(context, destRect, &destRectVisibleSubset);
237
238 // ClipRectToCanvas often overshoots, resulting in a larger region than our
239 // original destRect. Intersecting gets us back inside.
240 if (!destRectVisibleSubset.intersect(destRect))
241 return; // Nothing visible in destRect.
242
243 // Find the corresponding rect in the source image.
244 SkMatrix destToSrcTransform;
245 SkRect srcRectVisibleSubset;
246 destToSrcTransform.setRectToRect(destRect, srcRect, SkMatrix::kFill_ScaleToF it);
247 destToSrcTransform.mapRect(&srcRectVisibleSubset, destRectVisibleSubset);
248
249 SkRect scaledSrcRect;
250 SkBitmap scaledImageFragment = extractScaledImageFragment(srcRectVisibleSubs et, realScaleX, realScaleY, &scaledSrcRect);
251
252 context->drawBitmapRect(scaledImageFragment, &scaledSrcRect, destRectVisible Subset, &paint);
253 }
254
255 NativeImageSkia::NativeImageSkia()
256 : m_resolutionScale(1)
257 , m_resizeRequests(0)
258 {
259 }
260
261 NativeImageSkia::NativeImageSkia(const SkBitmap& other, float resolutionScale)
262 : m_image(other)
263 , m_resolutionScale(resolutionScale)
264 , m_resizeRequests(0)
265 {
266 }
267
268 NativeImageSkia::NativeImageSkia(const SkBitmap& image, float resolutionScale, c onst SkBitmap& resizedImage, const ImageResourceInfo& cachedImageInfo, int resiz eRequests)
269 : m_image(image)
270 , m_resolutionScale(resolutionScale)
271 , m_resizedImage(resizedImage)
272 , m_cachedImageInfo(cachedImageInfo)
273 , m_resizeRequests(resizeRequests)
274 {
275 }
276
277 NativeImageSkia::~NativeImageSkia()
278 {
279 }
280
281 int NativeImageSkia::decodedSize() const
282 {
283 return m_image.getSize() + m_resizedImage.getSize();
284 }
285
286 bool NativeImageSkia::hasResizedBitmap(const SkISize& scaledImageSize, const SkI Rect& scaledImageSubset) const
287 {
288 bool imageScaleEqual = m_cachedImageInfo.scaledImageSize == scaledImageSize;
289 bool scaledImageSubsetAvailable = m_cachedImageInfo.scaledImageSubset.contai ns(scaledImageSubset);
290 return imageScaleEqual && scaledImageSubsetAvailable && !m_resizedImage.empt y();
291 }
292
293 SkBitmap NativeImageSkia::resizedBitmap(const SkISize& scaledImageSize, const Sk IRect& scaledImageSubset) const
294 {
295 ASSERT(!DeferredImageDecoder::isLazyDecoded(m_image));
296
297 if (!hasResizedBitmap(scaledImageSize, scaledImageSubset)) {
298 bool shouldCache = isDataComplete()
299 && shouldCacheResampling(scaledImageSize, scaledImageSubset);
300
301 PlatformInstrumentation::willResizeImage(shouldCache);
302 SkBitmap resizedImage = skia::ImageOperations::Resize(m_image, skia::Ima geOperations::RESIZE_LANCZOS3, scaledImageSize.width(), scaledImageSize.height() , scaledImageSubset);
303 resizedImage.setImmutable();
304 PlatformInstrumentation::didResizeImage();
305
306 if (!shouldCache)
307 return resizedImage;
308
309 m_resizedImage = resizedImage;
310 }
311
312 SkBitmap resizedSubset;
313 SkIRect resizedSubsetRect = m_cachedImageInfo.rectInSubset(scaledImageSubset );
314 m_resizedImage.extractSubset(&resizedSubset, resizedSubsetRect);
315 return resizedSubset;
316 }
317
318 static bool hasNon90rotation(GraphicsContext* context)
319 {
320 return !context->getTotalMatrix().rectStaysRect();
321 }
322
323 void NativeImageSkia::draw(GraphicsContext* context, const SkRect& srcRect, cons t SkRect& destRect, PassRefPtr<SkXfermode> compOp) const
324 {
325 TRACE_EVENT0("skia", "NativeImageSkia::draw");
326 SkPaint paint;
327 paint.setXfermode(compOp.get());
328 paint.setColorFilter(context->colorFilter());
329 paint.setAlpha(context->getNormalizedAlpha());
330 paint.setLooper(context->drawLooper());
331 // only antialias if we're rotated or skewed
332 paint.setAntiAlias(hasNon90rotation(context));
333
334 ResamplingMode resampling;
335 if (context->isAccelerated()) {
336 resampling = LinearResampling;
337 } else if (context->printing()) {
338 resampling = NoResampling;
339 } else {
340 // Take into account scale applied to the canvas when computing sampling mode (e.g. CSS scale or page scale).
341 SkRect destRectTarget = destRect;
342 SkMatrix totalMatrix = context->getTotalMatrix();
343 if (!(totalMatrix.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPersp ective_Mask)))
344 totalMatrix.mapRect(&destRectTarget, destRect);
345
346 resampling = computeResamplingMode(totalMatrix,
347 SkScalarToFloat(srcRect.width()), SkScalarToFloat(srcRect.height()),
348 SkScalarToFloat(destRectTarget.width()), SkScalarToFloat(destRectTar get.height()));
349 }
350
351 if (resampling == NoResampling) {
352 // FIXME: This is to not break tests (it results in the filter bitmap fl ag
353 // being set to true). We need to decide if we respect NoResampling
354 // being returned from computeResamplingMode.
355 resampling = LinearResampling;
356 }
357 resampling = limitResamplingMode(context, resampling);
358 paint.setFilterBitmap(resampling == LinearResampling);
359
360 bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap());
361 // FIXME: Bicubic filtering in Skia is only applied to defer-decoded images
362 // as an experiment. Once this filtering code path becomes stable we should
363 // turn this on for all cases, including non-defer-decoded images.
364 bool useBicubicFilter = resampling == AwesomeResampling && isLazyDecoded;
365
366 if (useBicubicFilter)
367 paint.setFilterLevel(SkPaint::kHigh_FilterLevel);
368
369 if (resampling == AwesomeResampling && !useBicubicFilter) {
370 // Resample the image and then draw the result to canvas with bilinear
371 // filtering.
372 drawResampledBitmap(context, paint, srcRect, destRect);
373 } else {
374 // We want to filter it if we decided to do interpolation above, or if
375 // there is something interesting going on with the matrix (like a rotat ion).
376 // Note: for serialization, we will want to subset the bitmap first so w e
377 // don't send extra pixels.
378 context->drawBitmapRect(bitmap(), &srcRect, destRect, &paint);
379 }
380 if (isLazyDecoded)
381 PlatformInstrumentation::didDrawLazyPixelRef(reinterpret_cast<unsigned l ong long>(bitmap().pixelRef()));
382 context->didDrawRect(destRect, paint, &bitmap());
383 }
384
385 static SkBitmap createBitmapWithSpace(const SkBitmap& bitmap, int spaceWidth, in t spaceHeight)
386 {
387 SkBitmap result;
388 result.setConfig(bitmap.config(),
389 bitmap.width() + spaceWidth,
390 bitmap.height() + spaceHeight);
391 result.allocPixels();
392
393 result.eraseColor(SK_ColorTRANSPARENT);
394 bitmap.copyPixelsTo(reinterpret_cast<uint8_t*>(result.getPixels()), result.r owBytes() * result.height(), result.rowBytes());
395
396 return result;
397 }
398
399 void NativeImageSkia::drawPattern(
400 GraphicsContext* context,
401 const FloatRect& floatSrcRect,
402 const FloatSize& scale,
403 const FloatPoint& phase,
404 CompositeOperator compositeOp,
405 const FloatRect& destRect,
406 blink::WebBlendMode blendMode,
407 const IntSize& repeatSpacing) const
408 {
409 FloatRect normSrcRect = floatSrcRect;
410 normSrcRect.intersect(FloatRect(0, 0, bitmap().width(), bitmap().height()));
411 if (destRect.isEmpty() || normSrcRect.isEmpty())
412 return; // nothing to draw
413
414 SkMatrix totalMatrix = context->getTotalMatrix();
415 SkScalar ctmScaleX = totalMatrix.getScaleX();
416 SkScalar ctmScaleY = totalMatrix.getScaleY();
417 totalMatrix.preScale(scale.width(), scale.height());
418
419 // Figure out what size the bitmap will be in the destination. The
420 // destination rect is the bounds of the pattern, we need to use the
421 // matrix to see how big it will be.
422 SkRect destRectTarget;
423 totalMatrix.mapRect(&destRectTarget, normSrcRect);
424
425 float destBitmapWidth = SkScalarToFloat(destRectTarget.width());
426 float destBitmapHeight = SkScalarToFloat(destRectTarget.height());
427
428 // Compute the resampling mode.
429 ResamplingMode resampling;
430 if (context->isAccelerated() || context->printing())
431 resampling = LinearResampling;
432 else
433 resampling = computeResamplingMode(totalMatrix, normSrcRect.width(), nor mSrcRect.height(), destBitmapWidth, destBitmapHeight);
434 resampling = limitResamplingMode(context, resampling);
435
436 SkMatrix shaderTransform;
437 RefPtr<SkShader> shader;
438
439 bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap());
440 // Bicubic filter is only applied to defer-decoded images, see
441 // NativeImageSkia::draw for details.
442 bool useBicubicFilter = resampling == AwesomeResampling && isLazyDecoded;
443
444 if (resampling == AwesomeResampling && !useBicubicFilter) {
445 // Do nice resampling.
446 float scaleX = destBitmapWidth / normSrcRect.width();
447 float scaleY = destBitmapHeight / normSrcRect.height();
448 SkRect scaledSrcRect;
449
450 // The image fragment generated here is not exactly what is
451 // requested. The scale factor used is approximated and image
452 // fragment is slightly larger to align to integer
453 // boundaries.
454 SkBitmap resampled = extractScaledImageFragment(normSrcRect, scaleX, sca leY, &scaledSrcRect);
455 if (repeatSpacing.isZero()) {
456 shader = adoptRef(SkShader::CreateBitmapShader(resampled, SkShader:: kRepeat_TileMode, SkShader::kRepeat_TileMode));
457 } else {
458 shader = adoptRef(SkShader::CreateBitmapShader(
459 createBitmapWithSpace(resampled, repeatSpacing.width() * ctmScal eX, repeatSpacing.height() * ctmScaleY),
460 SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
461 }
462
463 // Since we just resized the bitmap, we need to remove the scale
464 // applied to the pixels in the bitmap shader. This means we need
465 // CTM * shaderTransform to have identity scale. Since we
466 // can't modify CTM (or the rectangle will be drawn in the wrong
467 // place), we must set shaderTransform's scale to the inverse of
468 // CTM scale.
469 shaderTransform.setScale(ctmScaleX ? 1 / ctmScaleX : 1, ctmScaleY ? 1 / ctmScaleY : 1);
470 } else {
471 // No need to resample before drawing.
472 SkBitmap srcSubset;
473 bitmap().extractSubset(&srcSubset, enclosingIntRect(normSrcRect));
474 if (repeatSpacing.isZero()) {
475 shader = adoptRef(SkShader::CreateBitmapShader(srcSubset, SkShader:: kRepeat_TileMode, SkShader::kRepeat_TileMode));
476 } else {
477 shader = adoptRef(SkShader::CreateBitmapShader(
478 createBitmapWithSpace(srcSubset, repeatSpacing.width() * ctmScal eX, repeatSpacing.height() * ctmScaleY),
479 SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode));
480 }
481
482 // Because no resizing occurred, the shader transform should be
483 // set to the pattern's transform, which just includes scale.
484 shaderTransform.setScale(scale.width(), scale.height());
485 }
486
487 // We also need to translate it such that the origin of the pattern is the
488 // origin of the destination rect, which is what WebKit expects. Skia uses
489 // the coordinate system origin as the base for the pattern. If WebKit wants
490 // a shifted image, it will shift it from there using the shaderTransform.
491 float adjustedX = phase.x() + normSrcRect.x() * scale.width();
492 float adjustedY = phase.y() + normSrcRect.y() * scale.height();
493 shaderTransform.postTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(ad justedY));
494 shader->setLocalMatrix(shaderTransform);
495
496 SkPaint paint;
497 paint.setShader(shader.get());
498 paint.setXfermode(WebCoreCompositeToSkiaComposite(compositeOp, blendMode).ge t());
499 paint.setColorFilter(context->colorFilter());
500
501 paint.setFilterBitmap(resampling == LinearResampling);
502 if (useBicubicFilter)
503 paint.setFilterLevel(SkPaint::kHigh_FilterLevel);
504 if (isLazyDecoded)
505 PlatformInstrumentation::didDrawLazyPixelRef(reinterpret_cast<unsigned l ong long>(bitmap().pixelRef()));
506
507 context->drawRect(destRect, paint);
508 }
509
510 bool NativeImageSkia::shouldCacheResampling(const SkISize& scaledImageSize, cons t SkIRect& scaledImageSubset) const
511 {
512 // Check whether the requested dimensions match previous request.
513 bool matchesPreviousRequest = m_cachedImageInfo.isEqual(scaledImageSize, sca ledImageSubset);
514 if (matchesPreviousRequest)
515 ++m_resizeRequests;
516 else {
517 m_cachedImageInfo.set(scaledImageSize, scaledImageSubset);
518 m_resizeRequests = 0;
519 // Reset m_resizedImage now, because we don't distinguish
520 // between the last requested resize info and m_resizedImage's
521 // resize info.
522 m_resizedImage.reset();
523 }
524
525 // We can not cache incomplete frames. This might be a good optimization in
526 // the future, were we know how much of the frame has been decoded, so when
527 // we incrementally draw more of the image, we only have to resample the
528 // parts that are changed.
529 if (!isDataComplete())
530 return false;
531
532 // If the destination bitmap is excessively large, we'll never allow caching .
533 static const unsigned long long kLargeBitmapSize = 4096ULL * 4096ULL;
534 unsigned long long fullSize = static_cast<unsigned long long>(scaledImageSiz e.width()) * static_cast<unsigned long long>(scaledImageSize.height());
535 unsigned long long fragmentSize = static_cast<unsigned long long>(scaledImag eSubset.width()) * static_cast<unsigned long long>(scaledImageSubset.height());
536
537 if (fragmentSize > kLargeBitmapSize)
538 return false;
539
540 // If the destination bitmap is small, we'll always allow caching, since
541 // there is not very much penalty for computing it and it may come in handy.
542 static const unsigned kSmallBitmapSize = 4096;
543 if (fragmentSize <= kSmallBitmapSize)
544 return true;
545
546 // If "too many" requests have been made for this bitmap, we assume that
547 // many more will be made as well, and we'll go ahead and cache it.
548 static const int kManyRequestThreshold = 4;
549 if (m_resizeRequests >= kManyRequestThreshold)
550 return true;
551
552 // If more than 1/4 of the resized image is requested, it's worth caching.
553 return fragmentSize > fullSize / 4;
554 }
555
556 NativeImageSkia::ImageResourceInfo::ImageResourceInfo()
557 {
558 scaledImageSize.setEmpty();
559 scaledImageSubset.setEmpty();
560 }
561
562 bool NativeImageSkia::ImageResourceInfo::isEqual(const SkISize& otherScaledImage Size, const SkIRect& otherScaledImageSubset) const
563 {
564 return scaledImageSize == otherScaledImageSize && scaledImageSubset == other ScaledImageSubset;
565 }
566
567 void NativeImageSkia::ImageResourceInfo::set(const SkISize& otherScaledImageSize , const SkIRect& otherScaledImageSubset)
568 {
569 scaledImageSize = otherScaledImageSize;
570 scaledImageSubset = otherScaledImageSubset;
571 }
572
573 SkIRect NativeImageSkia::ImageResourceInfo::rectInSubset(const SkIRect& otherSca ledImageSubset)
574 {
575 if (!scaledImageSubset.contains(otherScaledImageSubset))
576 return SkIRect::MakeEmpty();
577 SkIRect subsetRect = otherScaledImageSubset;
578 subsetRect.offset(-scaledImageSubset.x(), -scaledImageSubset.y());
579 return subsetRect;
580 }
581
582 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/core/platform/graphics/skia/NativeImageSkia.h ('k') | Source/core/platform/graphics/skia/OpaqueRegionSkia.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698