OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2008, Google Inc. All rights reserved. | 2 * Copyright (c) 2008, Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 28 matching lines...) Expand all Loading... |
39 #include "platform/graphics/GraphicsContext.h" | 39 #include "platform/graphics/GraphicsContext.h" |
40 #include "platform/graphics/Image.h" | 40 #include "platform/graphics/Image.h" |
41 #include "platform/graphics/DeferredImageDecoder.h" | 41 #include "platform/graphics/DeferredImageDecoder.h" |
42 #include "platform/graphics/skia/SkiaUtils.h" | 42 #include "platform/graphics/skia/SkiaUtils.h" |
43 #include "skia/ext/image_operations.h" | 43 #include "skia/ext/image_operations.h" |
44 #include "third_party/skia/include/core/SkMatrix.h" | 44 #include "third_party/skia/include/core/SkMatrix.h" |
45 #include "third_party/skia/include/core/SkPaint.h" | 45 #include "third_party/skia/include/core/SkPaint.h" |
46 #include "third_party/skia/include/core/SkScalar.h" | 46 #include "third_party/skia/include/core/SkScalar.h" |
47 #include "third_party/skia/include/core/SkShader.h" | 47 #include "third_party/skia/include/core/SkShader.h" |
48 | 48 |
| 49 #include <algorithm> |
49 #include <math.h> | 50 #include <math.h> |
50 #include <limits> | 51 #include <limits> |
51 | 52 |
52 namespace WebCore { | 53 namespace WebCore { |
53 | 54 |
54 static bool nearlyIntegral(float value) | 55 static bool nearlyIntegral(float value) |
55 { | 56 { |
56 return fabs(value - floorf(value)) < std::numeric_limits<float>::epsilon(); | 57 return fabs(value - floorf(value)) < std::numeric_limits<float>::epsilon(); |
57 } | 58 } |
58 | 59 |
59 ResamplingMode NativeImageSkia::computeResamplingMode(const SkMatrix& matrix, fl
oat srcWidth, float srcHeight, float destWidth, float destHeight) const | 60 InterpolationQuality NativeImageSkia::computeInterpolationQuality(const SkMatrix
& matrix, float srcWidth, float srcHeight, float destWidth, float destHeight) co
nst |
60 { | 61 { |
61 // The percent change below which we will not resample. This usually means | 62 // 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 // an off-by-one error on the web page, and just doing nearest neighbor |
63 // sampling is usually good enough. | 64 // sampling is usually good enough. |
64 const float kFractionalChangeThreshold = 0.025f; | 65 const float kFractionalChangeThreshold = 0.025f; |
65 | 66 |
66 // Images smaller than this in either direction are considered "small" and | 67 // Images smaller than this in either direction are considered "small" and |
67 // are not resampled ever (see below). | 68 // are not resampled ever (see below). |
68 const int kSmallImageSizeThreshold = 8; | 69 const int kSmallImageSizeThreshold = 8; |
69 | 70 |
70 // The amount an image can be stretched in a single direction before we | 71 // 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 // say that it is being stretched so much that it must be a line or |
72 // background that doesn't need resampling. | 73 // background that doesn't need resampling. |
73 const float kLargeStretch = 3.0f; | 74 const float kLargeStretch = 3.0f; |
74 | 75 |
75 // Figure out if we should resample this image. We try to prune out some | 76 // 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 // common cases where resampling won't give us anything, since it is much |
77 // slower than drawing stretched. | 78 // slower than drawing stretched. |
78 float diffWidth = fabs(destWidth - srcWidth); | 79 float diffWidth = fabs(destWidth - srcWidth); |
79 float diffHeight = fabs(destHeight - srcHeight); | 80 float diffHeight = fabs(destHeight - srcHeight); |
80 bool widthNearlyEqual = diffWidth < std::numeric_limits<float>::epsilon(); | 81 bool widthNearlyEqual = diffWidth < std::numeric_limits<float>::epsilon(); |
81 bool heightNearlyEqual = diffHeight < std::numeric_limits<float>::epsilon(); | 82 bool heightNearlyEqual = diffHeight < std::numeric_limits<float>::epsilon(); |
82 // We don't need to resample if the source and destination are the same. | 83 // We don't need to resample if the source and destination are the same. |
83 if (widthNearlyEqual && heightNearlyEqual) | 84 if (widthNearlyEqual && heightNearlyEqual) |
84 return NoResampling; | 85 return InterpolationNone; |
85 | 86 |
86 if (srcWidth <= kSmallImageSizeThreshold | 87 if (srcWidth <= kSmallImageSizeThreshold |
87 || srcHeight <= kSmallImageSizeThreshold | 88 || srcHeight <= kSmallImageSizeThreshold |
88 || destWidth <= kSmallImageSizeThreshold | 89 || destWidth <= kSmallImageSizeThreshold |
89 || destHeight <= kSmallImageSizeThreshold) { | 90 || destHeight <= kSmallImageSizeThreshold) { |
90 // Small image detected. | 91 // Small image detected. |
91 | 92 |
92 // Resample in the case where the new size would be non-integral. | 93 // Resample in the case where the new size would be non-integral. |
93 // This can cause noticeable breaks in repeating patterns, except | 94 // This can cause noticeable breaks in repeating patterns, except |
94 // when the source image is only one pixel wide in that dimension. | 95 // 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 if ((!nearlyIntegral(destWidth) && srcWidth > 1 + std::numeric_limits<fl
oat>::epsilon()) |
96 || (!nearlyIntegral(destHeight) && srcHeight > 1 + std::numeric_limi
ts<float>::epsilon())) | 97 || (!nearlyIntegral(destHeight) && srcHeight > 1 + std::numeric_limi
ts<float>::epsilon())) |
97 return LinearResampling; | 98 return InterpolationLow; |
98 | 99 |
99 // Otherwise, don't resample small images. These are often used for | 100 // Otherwise, don't resample small images. These are often used for |
100 // borders and rules (think 1x1 images used to make lines). | 101 // borders and rules (think 1x1 images used to make lines). |
101 return NoResampling; | 102 return InterpolationNone; |
102 } | 103 } |
103 | 104 |
104 if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= d
estWidth) { | 105 if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= d
estWidth) { |
105 // Large image detected. | 106 // Large image detected. |
106 | 107 |
107 // Don't resample if it is being stretched a lot in only one direction. | 108 // 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 // 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 // (which might be large) and then is stretching it to fill some part |
110 // of the page. | 111 // of the page. |
111 if (widthNearlyEqual || heightNearlyEqual) | 112 if (widthNearlyEqual || heightNearlyEqual) |
112 return NoResampling; | 113 return InterpolationNone; |
113 | 114 |
114 // The image is growing a lot and in more than one direction. Resampling | 115 // 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 // is slow and doesn't give us very much when growing a lot. |
116 return LinearResampling; | 117 return InterpolationLow; |
117 } | 118 } |
118 | 119 |
119 if ((diffWidth / srcWidth < kFractionalChangeThreshold) | 120 if ((diffWidth / srcWidth < kFractionalChangeThreshold) |
120 && (diffHeight / srcHeight < kFractionalChangeThreshold)) { | 121 && (diffHeight / srcHeight < kFractionalChangeThreshold)) { |
121 // It is disappointingly common on the web for image sizes to be off by | 122 // 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 // one or two pixels. We don't bother resampling if the size difference |
123 // is a small fraction of the original size. | 124 // is a small fraction of the original size. |
124 return NoResampling; | 125 return InterpolationNone; |
125 } | 126 } |
126 | 127 |
127 // When the image is not yet done loading, use linear. We don't cache the | 128 // 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 // partially resampled images, and as they come in incrementally, it causes |
129 // us to have to resample the whole thing every time. | 130 // us to have to resample the whole thing every time. |
130 if (!isDataComplete()) | 131 if (!isDataComplete()) |
131 return LinearResampling; | 132 return InterpolationLow; |
132 | 133 |
133 // Everything else gets resampled. | 134 // Everything else gets resampled. |
134 // High quality interpolation only enabled for scaling and translation. | 135 // High quality interpolation only enabled for scaling and translation. |
135 if (!(matrix.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Ma
sk))) | 136 if (!(matrix.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Ma
sk))) |
136 return AwesomeResampling; | 137 return InterpolationHigh; |
137 | 138 |
138 return LinearResampling; | 139 return InterpolationLow; |
139 } | 140 } |
140 | 141 |
141 static ResamplingMode limitResamplingMode(GraphicsContext* context, ResamplingMo
de resampling) | 142 static InterpolationQuality limitInterpolationQuality(GraphicsContext* context,
InterpolationQuality resampling) |
142 { | 143 { |
143 switch (context->imageInterpolationQuality()) { | 144 return std::min(resampling, context->imageInterpolationQuality()); |
144 case InterpolationNone: | |
145 return NoResampling; | |
146 case InterpolationMedium: | |
147 if (resampling == AwesomeResampling) | |
148 return LinearWithMipmapsResampling; | |
149 break; | |
150 case InterpolationLow: | |
151 if (resampling == AwesomeResampling || resampling == LinearWithMipmapsRe
sampling) | |
152 return LinearResampling; | |
153 break; | |
154 case InterpolationHigh: | |
155 break; | |
156 } | |
157 | |
158 return resampling; | |
159 } | 145 } |
160 | 146 |
161 static SkPaint::FilterLevel convertToSkiaFilterLevel(bool useBicubicFilter, Resa
mplingMode resampling) | 147 static SkPaint::FilterLevel convertToSkiaFilterLevel(bool useBicubicFilter, Inte
rpolationQuality resampling) |
162 { | 148 { |
| 149 // FIXME: If we get rid of this special case, this function can go away enti
rely. |
163 if (useBicubicFilter) | 150 if (useBicubicFilter) |
164 return SkPaint::kHigh_FilterLevel; | 151 return SkPaint::kHigh_FilterLevel; |
165 | 152 |
166 switch (resampling) { | 153 // InterpolationHigh if useBicubicFilter is false means that we do |
167 case LinearWithMipmapsResampling: | |
168 return SkPaint::kMedium_FilterLevel; | |
169 case LinearResampling: | |
170 return SkPaint::kLow_FilterLevel; | |
171 // AwesomeResampling if useBicubicFilter is false means that we do | |
172 // a manual high quality resampling before drawing to Skia. | 154 // a manual high quality resampling before drawing to Skia. |
173 case AwesomeResampling: | 155 if (resampling == InterpolationHigh) |
174 default: | |
175 return SkPaint::kNone_FilterLevel; | 156 return SkPaint::kNone_FilterLevel; |
176 } | 157 |
| 158 return static_cast<SkPaint::FilterLevel>(resampling); |
177 } | 159 } |
178 | 160 |
179 // This function is used to scale an image and extract a scaled fragment. | 161 // This function is used to scale an image and extract a scaled fragment. |
180 // | 162 // |
181 // ALGORITHM | 163 // ALGORITHM |
182 // | 164 // |
183 // Because the scaled image size has to be integers, we approximate the real | 165 // Because the scaled image size has to be integers, we approximate the real |
184 // scale with the following formula (only X direction is shown): | 166 // scale with the following formula (only X direction is shown): |
185 // | 167 // |
186 // scaledImageWidth = round(scaleX * imageRect.width()) | 168 // scaledImageWidth = round(scaleX * imageRect.width()) |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 TRACE_EVENT0("skia", "NativeImageSkia::draw"); | 352 TRACE_EVENT0("skia", "NativeImageSkia::draw"); |
371 SkPaint paint; | 353 SkPaint paint; |
372 paint.setXfermode(compOp.get()); | 354 paint.setXfermode(compOp.get()); |
373 paint.setColorFilter(context->colorFilter()); | 355 paint.setColorFilter(context->colorFilter()); |
374 paint.setAlpha(context->getNormalizedAlpha()); | 356 paint.setAlpha(context->getNormalizedAlpha()); |
375 paint.setLooper(context->drawLooper()); | 357 paint.setLooper(context->drawLooper()); |
376 paint.setAntiAlias(shouldDrawAntiAliased(context, destRect)); | 358 paint.setAntiAlias(shouldDrawAntiAliased(context, destRect)); |
377 | 359 |
378 bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap()); | 360 bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap()); |
379 | 361 |
380 ResamplingMode resampling; | 362 InterpolationQuality resampling; |
381 if (context->isAccelerated()) { | 363 if (context->isAccelerated()) { |
382 resampling = LinearResampling; | 364 resampling = InterpolationLow; |
383 } else if (context->printing()) { | 365 } else if (context->printing()) { |
384 resampling = NoResampling; | 366 resampling = InterpolationNone; |
385 } else if (isLazyDecoded) { | 367 } else if (isLazyDecoded) { |
386 resampling = AwesomeResampling; | 368 resampling = InterpolationHigh; |
387 } else { | 369 } else { |
388 // Take into account scale applied to the canvas when computing sampling
mode (e.g. CSS scale or page scale). | 370 // Take into account scale applied to the canvas when computing sampling
mode (e.g. CSS scale or page scale). |
389 SkRect destRectTarget = destRect; | 371 SkRect destRectTarget = destRect; |
390 SkMatrix totalMatrix = context->getTotalMatrix(); | 372 SkMatrix totalMatrix = context->getTotalMatrix(); |
391 if (!(totalMatrix.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPersp
ective_Mask))) | 373 if (!(totalMatrix.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPersp
ective_Mask))) |
392 totalMatrix.mapRect(&destRectTarget, destRect); | 374 totalMatrix.mapRect(&destRectTarget, destRect); |
393 | 375 |
394 resampling = computeResamplingMode(totalMatrix, | 376 resampling = computeInterpolationQuality(totalMatrix, |
395 SkScalarToFloat(srcRect.width()), SkScalarToFloat(srcRect.height()), | 377 SkScalarToFloat(srcRect.width()), SkScalarToFloat(srcRect.height()), |
396 SkScalarToFloat(destRectTarget.width()), SkScalarToFloat(destRectTar
get.height())); | 378 SkScalarToFloat(destRectTarget.width()), SkScalarToFloat(destRectTar
get.height())); |
397 } | 379 } |
398 | 380 |
399 if (resampling == NoResampling) { | 381 if (resampling == InterpolationNone) { |
400 // FIXME: This is to not break tests (it results in the filter bitmap fl
ag | 382 // FIXME: This is to not break tests (it results in the filter bitmap fl
ag |
401 // being set to true). We need to decide if we respect NoResampling | 383 // being set to true). We need to decide if we respect InterpolationNone |
402 // being returned from computeResamplingMode. | 384 // being returned from computeInterpolationQuality. |
403 resampling = LinearResampling; | 385 resampling = InterpolationLow; |
404 } | 386 } |
405 resampling = limitResamplingMode(context, resampling); | 387 resampling = limitInterpolationQuality(context, resampling); |
406 | 388 |
407 // FIXME: Bicubic filtering in Skia is only applied to defer-decoded images | 389 // FIXME: Bicubic filtering in Skia is only applied to defer-decoded images |
408 // as an experiment. Once this filtering code path becomes stable we should | 390 // as an experiment. Once this filtering code path becomes stable we should |
409 // turn this on for all cases, including non-defer-decoded images. | 391 // turn this on for all cases, including non-defer-decoded images. |
410 bool useBicubicFilter = resampling == AwesomeResampling && isLazyDecoded; | 392 bool useBicubicFilter = resampling == InterpolationHigh && isLazyDecoded; |
411 | 393 |
412 paint.setFilterLevel(convertToSkiaFilterLevel(useBicubicFilter, resampling))
; | 394 paint.setFilterLevel(convertToSkiaFilterLevel(useBicubicFilter, resampling))
; |
413 | 395 |
414 if (resampling == AwesomeResampling && !useBicubicFilter) { | 396 if (resampling == InterpolationHigh && !useBicubicFilter) { |
415 // Resample the image and then draw the result to canvas with bilinear | 397 // Resample the image and then draw the result to canvas with bilinear |
416 // filtering. | 398 // filtering. |
417 drawResampledBitmap(context, paint, srcRect, destRect); | 399 drawResampledBitmap(context, paint, srcRect, destRect); |
418 } else { | 400 } else { |
419 // We want to filter it if we decided to do interpolation above, or if | 401 // We want to filter it if we decided to do interpolation above, or if |
420 // there is something interesting going on with the matrix (like a rotat
ion). | 402 // there is something interesting going on with the matrix (like a rotat
ion). |
421 // Note: for serialization, we will want to subset the bitmap first so w
e | 403 // Note: for serialization, we will want to subset the bitmap first so w
e |
422 // don't send extra pixels. | 404 // don't send extra pixels. |
423 context->drawBitmapRect(bitmap(), &srcRect, destRect, &paint); | 405 context->drawBitmapRect(bitmap(), &srcRect, destRect, &paint); |
424 } | 406 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
468 // matrix to see how big it will be. | 450 // matrix to see how big it will be. |
469 SkRect destRectTarget; | 451 SkRect destRectTarget; |
470 totalMatrix.mapRect(&destRectTarget, normSrcRect); | 452 totalMatrix.mapRect(&destRectTarget, normSrcRect); |
471 | 453 |
472 float destBitmapWidth = SkScalarToFloat(destRectTarget.width()); | 454 float destBitmapWidth = SkScalarToFloat(destRectTarget.width()); |
473 float destBitmapHeight = SkScalarToFloat(destRectTarget.height()); | 455 float destBitmapHeight = SkScalarToFloat(destRectTarget.height()); |
474 | 456 |
475 bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap()); | 457 bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap()); |
476 | 458 |
477 // Compute the resampling mode. | 459 // Compute the resampling mode. |
478 ResamplingMode resampling; | 460 InterpolationQuality resampling; |
479 if (context->isAccelerated() || context->printing()) | 461 if (context->isAccelerated() || context->printing()) |
480 resampling = LinearResampling; | 462 resampling = InterpolationLow; |
481 else if (isLazyDecoded) | 463 else if (isLazyDecoded) |
482 resampling = AwesomeResampling; | 464 resampling = InterpolationHigh; |
483 else | 465 else |
484 resampling = computeResamplingMode(totalMatrix, normSrcRect.width(), nor
mSrcRect.height(), destBitmapWidth, destBitmapHeight); | 466 resampling = computeInterpolationQuality(totalMatrix, normSrcRect.width(
), normSrcRect.height(), destBitmapWidth, destBitmapHeight); |
485 resampling = limitResamplingMode(context, resampling); | 467 resampling = limitInterpolationQuality(context, resampling); |
486 | 468 |
487 SkMatrix localMatrix; | 469 SkMatrix localMatrix; |
488 // We also need to translate it such that the origin of the pattern is the | 470 // We also need to translate it such that the origin of the pattern is the |
489 // origin of the destination rect, which is what WebKit expects. Skia uses | 471 // origin of the destination rect, which is what WebKit expects. Skia uses |
490 // the coordinate system origin as the base for the pattern. If WebKit wants | 472 // the coordinate system origin as the base for the pattern. If WebKit wants |
491 // a shifted image, it will shift it from there using the localMatrix. | 473 // a shifted image, it will shift it from there using the localMatrix. |
492 const float adjustedX = phase.x() + normSrcRect.x() * scale.width(); | 474 const float adjustedX = phase.x() + normSrcRect.x() * scale.width(); |
493 const float adjustedY = phase.y() + normSrcRect.y() * scale.height(); | 475 const float adjustedY = phase.y() + normSrcRect.y() * scale.height(); |
494 localMatrix.setTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(adjuste
dY)); | 476 localMatrix.setTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(adjuste
dY)); |
495 | 477 |
496 RefPtr<SkShader> shader; | 478 RefPtr<SkShader> shader; |
497 | 479 |
498 // Bicubic filter is only applied to defer-decoded images, see | 480 // Bicubic filter is only applied to defer-decoded images, see |
499 // NativeImageSkia::draw for details. | 481 // NativeImageSkia::draw for details. |
500 bool useBicubicFilter = resampling == AwesomeResampling && isLazyDecoded; | 482 bool useBicubicFilter = resampling == InterpolationHigh && isLazyDecoded; |
501 | 483 |
502 if (resampling == AwesomeResampling && !useBicubicFilter) { | 484 if (resampling == InterpolationHigh && !useBicubicFilter) { |
503 // Do nice resampling. | 485 // Do nice resampling. |
504 float scaleX = destBitmapWidth / normSrcRect.width(); | 486 float scaleX = destBitmapWidth / normSrcRect.width(); |
505 float scaleY = destBitmapHeight / normSrcRect.height(); | 487 float scaleY = destBitmapHeight / normSrcRect.height(); |
506 SkRect scaledSrcRect; | 488 SkRect scaledSrcRect; |
507 | 489 |
508 // Since we are resizing the bitmap, we need to remove the scale | 490 // Since we are resizing the bitmap, we need to remove the scale |
509 // applied to the pixels in the bitmap shader. This means we need | 491 // applied to the pixels in the bitmap shader. This means we need |
510 // CTM * localMatrix to have identity scale. Since we | 492 // CTM * localMatrix to have identity scale. Since we |
511 // can't modify CTM (or the rectangle will be drawn in the wrong | 493 // can't modify CTM (or the rectangle will be drawn in the wrong |
512 // place), we must set localMatrix's scale to the inverse of | 494 // place), we must set localMatrix's scale to the inverse of |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
620 SkIRect NativeImageSkia::ImageResourceInfo::rectInSubset(const SkIRect& otherSca
ledImageSubset) | 602 SkIRect NativeImageSkia::ImageResourceInfo::rectInSubset(const SkIRect& otherSca
ledImageSubset) |
621 { | 603 { |
622 if (!scaledImageSubset.contains(otherScaledImageSubset)) | 604 if (!scaledImageSubset.contains(otherScaledImageSubset)) |
623 return SkIRect::MakeEmpty(); | 605 return SkIRect::MakeEmpty(); |
624 SkIRect subsetRect = otherScaledImageSubset; | 606 SkIRect subsetRect = otherScaledImageSubset; |
625 subsetRect.offset(-scaledImageSubset.x(), -scaledImageSubset.y()); | 607 subsetRect.offset(-scaledImageSubset.x(), -scaledImageSubset.y()); |
626 return subsetRect; | 608 return subsetRect; |
627 } | 609 } |
628 | 610 |
629 } // namespace WebCore | 611 } // namespace WebCore |
OLD | NEW |