OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2006,2007,2008, Google Inc. All rights reserved. | 2 * Copyright (c) 2006,2007,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 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 result.setTranslateY(WebCoreDoubleToSkScalar(source.f())); | 182 result.setTranslateY(WebCoreDoubleToSkScalar(source.f())); |
183 | 183 |
184 // FIXME: Set perspective properly. | 184 // FIXME: Set perspective properly. |
185 result.setPerspX(0); | 185 result.setPerspX(0); |
186 result.setPerspY(0); | 186 result.setPerspY(0); |
187 result.set(SkMatrix::kMPersp2, SK_Scalar1); | 187 result.set(SkMatrix::kMPersp2, SK_Scalar1); |
188 | 188 |
189 return result; | 189 return result; |
190 } | 190 } |
191 | 191 |
| 192 bool nearlyIntegral(float value) |
| 193 { |
| 194 return fabs(value - floorf(value)) < std::numeric_limits<float>::epsilon(); |
| 195 } |
| 196 |
| 197 InterpolationQuality limitInterpolationQuality(const GraphicsContext* context, I
nterpolationQuality resampling) |
| 198 { |
| 199 return std::min(resampling, context->imageInterpolationQuality()); |
| 200 } |
| 201 |
| 202 SkPaint::FilterLevel convertToSkiaFilterLevel(bool useBicubicFilter, Interpolati
onQuality resampling) |
| 203 { |
| 204 // FIXME: If we get rid of this special case, this function can go away enti
rely. |
| 205 if (useBicubicFilter) |
| 206 return SkPaint::kHigh_FilterLevel; |
| 207 |
| 208 // InterpolationHigh if useBicubicFilter is false means that we do |
| 209 // a manual high quality resampling before drawing to Skia. |
| 210 if (resampling == InterpolationHigh) |
| 211 return SkPaint::kNone_FilterLevel; |
| 212 |
| 213 return static_cast<SkPaint::FilterLevel>(resampling); |
| 214 } |
| 215 |
| 216 InterpolationQuality computeInterpolationQuality( |
| 217 const SkMatrix& matrix, |
| 218 float srcWidth, |
| 219 float srcHeight, |
| 220 float destWidth, |
| 221 float destHeight, |
| 222 bool isDataComplete) |
| 223 { |
| 224 // The percent change below which we will not resample. This usually means |
| 225 // an off-by-one error on the web page, and just doing nearest neighbor |
| 226 // sampling is usually good enough. |
| 227 const float kFractionalChangeThreshold = 0.025f; |
| 228 |
| 229 // Images smaller than this in either direction are considered "small" and |
| 230 // are not resampled ever (see below). |
| 231 const int kSmallImageSizeThreshold = 8; |
| 232 |
| 233 // The amount an image can be stretched in a single direction before we |
| 234 // say that it is being stretched so much that it must be a line or |
| 235 // background that doesn't need resampling. |
| 236 const float kLargeStretch = 3.0f; |
| 237 |
| 238 // Figure out if we should resample this image. We try to prune out some |
| 239 // common cases where resampling won't give us anything, since it is much |
| 240 // slower than drawing stretched. |
| 241 float diffWidth = fabs(destWidth - srcWidth); |
| 242 float diffHeight = fabs(destHeight - srcHeight); |
| 243 bool widthNearlyEqual = diffWidth < std::numeric_limits<float>::epsilon(); |
| 244 bool heightNearlyEqual = diffHeight < std::numeric_limits<float>::epsilon(); |
| 245 // We don't need to resample if the source and destination are the same. |
| 246 if (widthNearlyEqual && heightNearlyEqual) |
| 247 return InterpolationNone; |
| 248 |
| 249 if (srcWidth <= kSmallImageSizeThreshold |
| 250 || srcHeight <= kSmallImageSizeThreshold |
| 251 || destWidth <= kSmallImageSizeThreshold |
| 252 || destHeight <= kSmallImageSizeThreshold) { |
| 253 // Small image detected. |
| 254 |
| 255 // Resample in the case where the new size would be non-integral. |
| 256 // This can cause noticeable breaks in repeating patterns, except |
| 257 // when the source image is only one pixel wide in that dimension. |
| 258 if ((!nearlyIntegral(destWidth) && srcWidth > 1 + std::numeric_limits<fl
oat>::epsilon()) |
| 259 || (!nearlyIntegral(destHeight) && srcHeight > 1 + std::numeric_limi
ts<float>::epsilon())) |
| 260 return InterpolationLow; |
| 261 |
| 262 // Otherwise, don't resample small images. These are often used for |
| 263 // borders and rules (think 1x1 images used to make lines). |
| 264 return InterpolationNone; |
| 265 } |
| 266 |
| 267 if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= d
estWidth) { |
| 268 // Large image detected. |
| 269 |
| 270 // Don't resample if it is being stretched a lot in only one direction. |
| 271 // This is trying to catch cases where somebody has created a border |
| 272 // (which might be large) and then is stretching it to fill some part |
| 273 // of the page. |
| 274 if (widthNearlyEqual || heightNearlyEqual) |
| 275 return InterpolationNone; |
| 276 |
| 277 // The image is growing a lot and in more than one direction. Resampling |
| 278 // is slow and doesn't give us very much when growing a lot. |
| 279 return InterpolationLow; |
| 280 } |
| 281 |
| 282 if ((diffWidth / srcWidth < kFractionalChangeThreshold) |
| 283 && (diffHeight / srcHeight < kFractionalChangeThreshold)) { |
| 284 // It is disappointingly common on the web for image sizes to be off by |
| 285 // one or two pixels. We don't bother resampling if the size difference |
| 286 // is a small fraction of the original size. |
| 287 return InterpolationNone; |
| 288 } |
| 289 |
| 290 // When the image is not yet done loading, use linear. We don't cache the |
| 291 // partially resampled images, and as they come in incrementally, it causes |
| 292 // us to have to resample the whole thing every time. |
| 293 if (!isDataComplete) |
| 294 return InterpolationLow; |
| 295 |
| 296 // Everything else gets resampled. |
| 297 // High quality interpolation only enabled for scaling and translation. |
| 298 if (!(matrix.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Ma
sk))) |
| 299 return InterpolationHigh; |
| 300 |
| 301 return InterpolationLow; |
| 302 } |
| 303 |
| 304 |
| 305 bool shouldDrawAntiAliased(const GraphicsContext* context, const SkRect& destRec
t) |
| 306 { |
| 307 if (!context->shouldAntialias()) |
| 308 return false; |
| 309 const SkMatrix totalMatrix = context->getTotalMatrix(); |
| 310 // Don't disable anti-aliasing if we're rotated or skewed. |
| 311 if (!totalMatrix.rectStaysRect()) |
| 312 return true; |
| 313 // Disable anti-aliasing for scales or n*90 degree rotations. |
| 314 // Allow to opt out of the optimization though for "hairline" geometry |
| 315 // images - using the shouldAntialiasHairlineImages() GraphicsContext flag. |
| 316 if (!context->shouldAntialiasHairlineImages()) |
| 317 return false; |
| 318 // Check if the dimensions of the destination are "small" (less than one |
| 319 // device pixel). To prevent sudden drop-outs. Since we know that |
| 320 // kRectStaysRect_Mask is set, the matrix either has scale and no skew or |
| 321 // vice versa. We can query the kAffine_Mask flag to determine which case |
| 322 // it is. |
| 323 // FIXME: This queries the CTM while drawing, which is generally |
| 324 // discouraged. Always drawing with AA can negatively impact performance |
| 325 // though - that's why it's not always on. |
| 326 SkScalar widthExpansion, heightExpansion; |
| 327 if (totalMatrix.getType() & SkMatrix::kAffine_Mask) |
| 328 widthExpansion = totalMatrix[SkMatrix::kMSkewY], heightExpansion = total
Matrix[SkMatrix::kMSkewX]; |
| 329 else |
| 330 widthExpansion = totalMatrix[SkMatrix::kMScaleX], heightExpansion = tota
lMatrix[SkMatrix::kMScaleY]; |
| 331 return destRect.width() * fabs(widthExpansion) < 1 || destRect.height() * fa
bs(heightExpansion) < 1; |
| 332 } |
| 333 |
192 } // namespace blink | 334 } // namespace blink |
OLD | NEW |