diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-01 20:16:56 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-01 20:16:56 +0000 |
commit | 15e46d28735180ebb5e57464a50f7a1117729b81 (patch) | |
tree | 8cf5a3d49a5a0eb6e50074fa14771623248ee3a2 | |
parent | 4c3fe4ae337c8661c6370099bea9a5bcf5faf270 (diff) | |
download | chromium_src-15e46d28735180ebb5e57464a50f7a1117729b81.zip chromium_src-15e46d28735180ebb5e57464a50f7a1117729b81.tar.gz chromium_src-15e46d28735180ebb5e57464a50f7a1117729b81.tar.bz2 |
Add library support for subpixel rendering of images during Resize().
BUG=34809
TEST=No test since inactive by default. For a very manual test, modify Resize()
to only call the subpixel variant. Then go to your favorite web page (with some
image) and choose Zoom > Smaller
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40292 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | skia/ext/image_operations.cc | 114 | ||||
-rw-r--r-- | skia/ext/image_operations.h | 16 |
2 files changed, 128 insertions, 2 deletions
diff --git a/skia/ext/image_operations.cc b/skia/ext/image_operations.cc index ed4673b..f6ee4ca 100644 --- a/skia/ext/image_operations.cc +++ b/skia/ext/image_operations.cc @@ -13,9 +13,12 @@ #include "base/logging.h" #include "base/stack_container.h" #include "base/time.h" +#include "build/build_config.h" #include "skia/ext/convolver.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkRect.h" +#include "third_party/skia/include/core/SkFontHost.h" +#include "third_party/skia/include/core/SkColorPriv.h" namespace skia { @@ -256,6 +259,116 @@ SkBitmap ImageOperations::Resize(const SkBitmap& source, ResizeMethod method, int dest_width, int dest_height, const SkIRect& dest_subset) { + if (method == ImageOperations::RESIZE_SUBPIXEL) + return ResizeSubpixel(source, dest_width, dest_height, dest_subset); + else + return ResizeBasic(source, method, dest_width, dest_height, dest_subset); +} + +// static +SkBitmap ImageOperations::ResizeSubpixel(const SkBitmap& source, + int dest_width, int dest_height, + const SkIRect& dest_subset) { + // Currently only works on Linux because this is the only platform where + // SkFontHost::GetSubpixelOrder is defined. +#if defined(OS_LINUX) + // Understand the display. + const SkFontHost::LCDOrder order = SkFontHost::GetSubpixelOrder(); + const SkFontHost::LCDOrientation orientation = + SkFontHost::GetSubpixelOrientation(); + + // Decide on which dimension, if any, to deploy subpixel rendering. + int w = 1; + int h = 1; + switch (orientation) { + case SkFontHost::kHorizontal_LCDOrientation: + w = dest_width < source.width() ? 3 : 1; + break; + case SkFontHost::kVertical_LCDOrientation: + h = dest_height < source.height() ? 3 : 1; + break; + } + + // Resize the image. + const int width = dest_width * w; + const int height = dest_height * h; + SkIRect subset = { dest_subset.fLeft, dest_subset.fTop, + dest_subset.fLeft + dest_subset.width() * w, + dest_subset.fTop + dest_subset.height() * h }; + SkBitmap img = ResizeBasic(source, ImageOperations::RESIZE_LANCZOS3, width, + height, subset); + const int row_words = img.rowBytes() / 4; + if (w == 1 && h == 1) + return img; + + // Render into subpixels. + SkBitmap result; + result.setConfig(SkBitmap::kARGB_8888_Config, dest_subset.width(), + dest_subset.height()); + result.allocPixels(); + SkAutoLockPixels locker(img); + uint32* src_row = img.getAddr32(0, 0); + uint32* dst_row = result.getAddr32(0, 0); + for (int y = 0; y < dest_subset.height(); y++) { + uint32* src = src_row; + uint32* dst = dst_row; + for (int x = 0; x < dest_subset.width(); x++, src += w, dst++) { + uint8 r, g, b, a; + switch (order) { + case SkFontHost::kRGB_LCDOrder: + switch (orientation) { + case SkFontHost::kHorizontal_LCDOrientation: + r = SkGetPackedR32(src[0]); + g = SkGetPackedG32(src[1]); + b = SkGetPackedB32(src[2]); + a = SkGetPackedA32(src[1]); + break; + case SkFontHost::kVertical_LCDOrientation: + r = SkGetPackedR32(src[0 * row_words]); + g = SkGetPackedG32(src[1 * row_words]); + b = SkGetPackedB32(src[2 * row_words]); + a = SkGetPackedA32(src[1 * row_words]); + break; + } + break; + case SkFontHost::kBGR_LCDOrder: + switch (orientation) { + case SkFontHost::kHorizontal_LCDOrientation: + b = SkGetPackedB32(src[0]); + g = SkGetPackedG32(src[1]); + r = SkGetPackedR32(src[2]); + a = SkGetPackedA32(src[1]); + break; + case SkFontHost::kVertical_LCDOrientation: + b = SkGetPackedB32(src[0 * row_words]); + g = SkGetPackedG32(src[1 * row_words]); + r = SkGetPackedR32(src[2 * row_words]); + a = SkGetPackedA32(src[1 * row_words]); + break; + } + break; + } + // Premultiplied alpha is very fragile. + a = a > r ? a : r; + a = a > g ? a : g; + a = a > b ? a : b; + *dst = SkPackARGB32(a, r, g, b); + } + src_row += h * row_words; + dst_row += result.rowBytes() / 4; + } + result.setIsOpaque(img.isOpaque()); + return result; +#else + return SkBitmap(); +#endif // OS_LINUX +} + +// static +SkBitmap ImageOperations::ResizeBasic(const SkBitmap& source, + ResizeMethod method, + int dest_width, int dest_height, + const SkIRect& dest_subset) { // Time how long this takes to see if it's a problem for users. base::TimeTicks resize_start = base::TimeTicks::Now(); @@ -307,4 +420,3 @@ SkBitmap ImageOperations::Resize(const SkBitmap& source, } } // namespace skia - diff --git a/skia/ext/image_operations.h b/skia/ext/image_operations.h index e9f448b..0d92d83 100644 --- a/skia/ext/image_operations.h +++ b/skia/ext/image_operations.h @@ -23,6 +23,10 @@ class ImageOperations { // 3-cycle Lanczos filter. This is tall in the middle, goes negative on // each side, then oscillates 2 more times. It gives nice sharp edges. RESIZE_LANCZOS3, + + // Lanczos filter + subpixel interpolation. If subpixel rendering is not + // appropriate we automatically fall back to Lanczos. + RESIZE_SUBPIXEL, }; // Resizes the given source bitmap using the specified resize method, so that @@ -46,9 +50,19 @@ class ImageOperations { private: ImageOperations(); // Class for scoping only. + + // Supports all methods except RESIZE_SUBPIXEL. + static SkBitmap ResizeBasic(const SkBitmap& source, + ResizeMethod method, + int dest_width, int dest_height, + const SkIRect& dest_subset); + + // Subpixel renderer. + static SkBitmap ResizeSubpixel(const SkBitmap& source, + int dest_width, int dest_height, + const SkIRect& dest_subset); }; } // namespace skia #endif // SKIA_EXT_IMAGE_OPERATIONS_H_ - |