From ae615162135445eb0b94365b1a1cfa511e7f4be4 Mon Sep 17 00:00:00 2001 From: "brettw@google.com" Date: Wed, 3 Dec 2008 01:11:58 +0000 Subject: Revert my skia file moves because of layout test failures. Review URL: http://codereview.chromium.org/12892 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@6266 0039d316-1c4b-4281-b951-d872f2087c98 --- base/base.xcodeproj/project.pbxproj | 10 + base/base_unittests.scons | 2 + base/build/base_gfx.vcproj | 24 ++ base/build/base_unittests.vcproj | 8 + base/gfx/base_gfx.scons | 4 + base/gfx/convolver.cc | 335 +++++++++++++++++++ base/gfx/convolver.h | 137 ++++++++ base/gfx/convolver_unittest.cc | 127 +++++++ base/gfx/image_operations.cc | 362 ++++++++++++++++++++ base/gfx/image_operations.h | 63 ++++ base/gfx/image_operations_unittest.cc | 148 +++++++++ base/gfx/img_resize_perftest.cc | 70 ++++ base/gfx/native_theme.cc | 12 +- base/gfx/skia_utils.cc | 75 +++++ base/gfx/skia_utils.h | 56 ++++ base/gfx/skia_utils_mac.cc | 83 +++++ base/gfx/skia_utils_mac.h | 51 +++ chrome/browser/autocomplete/autocomplete_edit.cc | 1 + chrome/browser/download/download_util.cc | 2 +- chrome/browser/fav_icon_helper.cc | 6 +- chrome/browser/importer/importer.cc | 6 +- chrome/browser/views/bookmark_bar_view.cc | 30 +- chrome/browser/views/bookmark_manager_view.cc | 5 +- chrome/browser/views/options/content_page_view.cc | 4 +- chrome/browser/views/options/fonts_page_view.cc | 1 + .../browser/views/options/languages_page_view.cc | 1 + chrome/browser/views/options/options_group_view.cc | 1 + chrome/browser/views/sad_tab_view.cc | 13 +- chrome/browser/views/tabs/tab_renderer.cc | 8 +- chrome/common/gfx/color_utils.cc | 7 +- chrome/common/gfx/icon_util.cc | 7 +- chrome/renderer/render_view.cc | 7 +- chrome/views/background.cc | 4 +- chrome/views/button.cc | 4 +- chrome/views/chrome_menu.cc | 1 + chrome/views/single_split_view.cc | 4 +- chrome/views/tabbed_pane.cc | 1 + chrome/views/table_view.cc | 8 +- chrome/views/text_field.cc | 5 +- skia/SConscript | 6 - skia/ext/bitmap_platform_device_mac.cc | 2 +- skia/ext/convolver.cc | 336 ------------------- skia/ext/convolver.h | 137 -------- skia/ext/convolver_unittest.cc | 128 ------- skia/ext/image_operations.cc | 366 --------------------- skia/ext/image_operations.h | 63 ---- skia/ext/image_operations_unittest.cc | 149 --------- skia/ext/platform_device_mac.cc | 2 +- skia/ext/platform_device_win.cc | 5 +- skia/ext/skia_utils.cc | 26 -- skia/ext/skia_utils.h | 23 -- skia/ext/skia_utils_mac.cc | 83 ----- skia/ext/skia_utils_mac.h | 51 --- skia/ext/skia_utils_win.cc | 59 ---- skia/ext/skia_utils_win.h | 56 ---- skia/ext/vector_device.cc | 6 +- skia/skia.vcproj | 32 -- skia/skia.xcodeproj/project.pbxproj | 12 - webkit/port/platform/graphics/FontWin.cpp | 6 +- webkit/port/platform/graphics/ImageSkia.cpp | 10 +- webkit/port/platform/graphics/NativeImageSkia.cpp | 10 +- .../port/platform/graphics/PlatformContextSkia.cpp | 2 + webkit/port/rendering/RenderThemeWin.cpp | 7 +- webkit/tools/test_shell/test_shell_tests.vcproj | 8 - 64 files changed, 1654 insertions(+), 1624 deletions(-) create mode 100644 base/gfx/convolver.cc create mode 100644 base/gfx/convolver.h create mode 100644 base/gfx/convolver_unittest.cc create mode 100644 base/gfx/image_operations.cc create mode 100644 base/gfx/image_operations.h create mode 100644 base/gfx/image_operations_unittest.cc create mode 100644 base/gfx/img_resize_perftest.cc create mode 100644 base/gfx/skia_utils.cc create mode 100644 base/gfx/skia_utils.h create mode 100644 base/gfx/skia_utils_mac.cc create mode 100644 base/gfx/skia_utils_mac.h delete mode 100644 skia/ext/convolver.cc delete mode 100644 skia/ext/convolver.h delete mode 100644 skia/ext/convolver_unittest.cc delete mode 100644 skia/ext/image_operations.cc delete mode 100644 skia/ext/image_operations.h delete mode 100644 skia/ext/image_operations_unittest.cc delete mode 100644 skia/ext/skia_utils.cc delete mode 100644 skia/ext/skia_utils.h delete mode 100644 skia/ext/skia_utils_mac.cc delete mode 100644 skia/ext/skia_utils_mac.h delete mode 100644 skia/ext/skia_utils_win.cc delete mode 100644 skia/ext/skia_utils_win.h diff --git a/base/base.xcodeproj/project.pbxproj b/base/base.xcodeproj/project.pbxproj index ad7a0dd..1663719 100644 --- a/base/base.xcodeproj/project.pbxproj +++ b/base/base.xcodeproj/project.pbxproj @@ -82,6 +82,7 @@ 7B836E180E55CE5B00F6AD31 /* libicudata.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B836D970E55CE4700F6AD31 /* libicudata.a */; }; 7B8505B30E5B432200730B43 /* size.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7B8505A40E5B3FBE00730B43 /* size.cc */; }; 7B8505D30E5B43EE00730B43 /* rect_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = E45629E40E27C058005E4685 /* rect_unittest.cc */; }; + 7B8505D40E5B43FE00730B43 /* convolver_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = E48A06790E3F714300172919 /* convolver_unittest.cc */; }; 7B8505D50E5B441000730B43 /* png_codec_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = E4562A200E27C8C1005E4685 /* png_codec_unittest.cc */; }; 7B8505D90E5B445100730B43 /* libbase_gfx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 825403B10D92D2E50006B936 /* libbase_gfx.a */; }; 7B85062A0E5B556900730B43 /* libpng.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B165D5E0E55081400185273 /* libpng.a */; }; @@ -149,7 +150,10 @@ A5A0270B0E4A630D00498DA9 /* file_util_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = A5A0270A0E4A630D00498DA9 /* file_util_mac.mm */; }; A5CE1D2B0E55F4D800AD0606 /* file_util_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = A5A0282D0E4CFA8500498DA9 /* file_util_unittest.cc */; }; AB4C147D0EC0E3F600655FED /* time_mac.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BEB81490D9B0F33009BA8DD /* time_mac.cc */; }; + AB956E030E5DDB7A00BBE9D8 /* image_operations.cc in Sources */ = {isa = PBXBuildFile; fileRef = E48A06370E3F6C1F00172919 /* image_operations.cc */; }; + AB956E0A0E5DDC0900BBE9D8 /* image_operations_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = E48A063B0E3F6C3000172919 /* image_operations_unittest.cc */; }; ABE1BA2A0E7574D1009041DA /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ABE1BA290E7574D1009041DA /* ApplicationServices.framework */; }; + ABE1BA610E75757C009041DA /* skia_utils_mac.cc in Sources */ = {isa = PBXBuildFile; fileRef = ABE1BA600E75757C009041DA /* skia_utils_mac.cc */; }; ABF4B98F0DC2BA6900A6E319 /* base_paths_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABF4B98E0DC2BA6900A6E319 /* base_paths_mac.mm */; }; ABF4B99E0DC2BB6000A6E319 /* clipboard_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = ABF4B99D0DC2BB6000A6E319 /* clipboard_mac.mm */; }; ABF4B9AF0DC2BC6200A6E319 /* json_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8254031B0D92D1F40006B936 /* json_reader.cc */; }; @@ -175,6 +179,7 @@ BA73AA330E5F614B00A20026 /* condition_variable_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = BA73AA320E5F614B00A20026 /* condition_variable_unittest.cc */; }; E45062A60E40A9BE0025A81A /* base_switches.cc in Sources */ = {isa = PBXBuildFile; fileRef = 825402CB0D92D1390006B936 /* base_switches.cc */; }; E48A05F70E3F61B300172919 /* command_line.cc in Sources */ = {isa = PBXBuildFile; fileRef = E4A133490E37A41D00110AA2 /* command_line.cc */; }; + E48A06710E3F70E200172919 /* convolver.cc in Sources */ = {isa = PBXBuildFile; fileRef = E48A06680E3F70B500172919 /* convolver.cc */; }; E48FB9990EC4ED850052B72B /* process_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = E48FB9980EC4ED850052B72B /* process_posix.cc */; }; E48FB9EA0EC4F53B0052B72B /* process_util_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = E48FB9E90EC4F53B0052B72B /* process_util_mac.mm */; }; E49115EF0E47B461001EE8C3 /* at_exit.cc in Sources */ = {isa = PBXBuildFile; fileRef = E49115EC0E47B461001EE8C3 /* at_exit.cc */; }; @@ -1428,11 +1433,14 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + E48A06710E3F70E200172919 /* convolver.cc in Sources */, + AB956E030E5DDB7A00BBE9D8 /* image_operations.cc in Sources */, 825403EE0D92D31D0006B936 /* png_decoder.cc in Sources */, 825403F00D92D31D0006B936 /* png_encoder.cc in Sources */, 825403F20D92D31D0006B936 /* point.cc in Sources */, 825403F50D92D31D0006B936 /* rect.cc in Sources */, 7B8505B30E5B432200730B43 /* size.cc in Sources */, + ABE1BA610E75757C009041DA /* skia_utils_mac.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1445,6 +1453,7 @@ B52C916C0E9428F500208D01 /* clipboard_unittest.cc in Sources */, 7B78D38F0E54FE0100609465 /* command_line_unittest.cc in Sources */, BA73AA330E5F614B00A20026 /* condition_variable_unittest.cc in Sources */, + 7B8505D40E5B43FE00730B43 /* convolver_unittest.cc in Sources */, ABF68B2B0EB0F93E00E72835 /* field_trial_unittest.cc in Sources */, 4D11B89F0E929F0700EF7617 /* file_path_unittest.cc in Sources */, A5CE1D2B0E55F4D800AD0606 /* file_util_unittest.cc in Sources */, @@ -1452,6 +1461,7 @@ 93611B1A0E5A878400F9405D /* histogram_unittest.cc in Sources */, 7BAE392B0E6F4EF200C3F750 /* hmac_unittest.cc in Sources */, B57E4D780E9C26340090055D /* idletimer_unittest.cc in Sources */, + AB956E0A0E5DDC0900BBE9D8 /* image_operations_unittest.cc in Sources */, 7B78D3920E54FE0100609465 /* json_reader_unittest.cc in Sources */, 7B78D3930E54FE0100609465 /* json_writer_unittest.cc in Sources */, 7BF892E00E758883000BAF8A /* lazy_instance_unittest.cc in Sources */, diff --git a/base/base_unittests.scons b/base/base_unittests.scons index 1ba4ec6..d913bc8 100644 --- a/base/base_unittests.scons +++ b/base/base_unittests.scons @@ -93,6 +93,8 @@ input_files = [ 'word_iterator_unittest.cc', 'worker_pool_unittest.cc', + 'gfx/convolver_unittest.cc', + 'gfx/image_operations_unittest.cc', 'gfx/native_theme_unittest.cc', 'gfx/png_codec_unittest.cc', 'gfx/rect_unittest.cc', diff --git a/base/build/base_gfx.vcproj b/base/build/base_gfx.vcproj index 70875a9..ef4b5de 100644 --- a/base/build/base_gfx.vcproj +++ b/base/build/base_gfx.vcproj @@ -122,6 +122,14 @@ + + + + @@ -130,6 +138,14 @@ > + + + + @@ -177,6 +193,14 @@ RelativePath="..\gfx\size.h" > + + + + diff --git a/base/build/base_unittests.vcproj b/base/build/base_unittests.vcproj index e822992..3c75166 100644 --- a/base/build/base_unittests.vcproj +++ b/base/build/base_unittests.vcproj @@ -396,6 +396,14 @@ Name="gfx_tests" > + + + + diff --git a/base/gfx/base_gfx.scons b/base/gfx/base_gfx.scons index a69206b..7173340 100644 --- a/base/gfx/base_gfx.scons +++ b/base/gfx/base_gfx.scons @@ -25,13 +25,16 @@ if env['PLATFORM'] == 'win32': ) input_files = [ + 'convolver.cc', 'gdi_util.cc', + 'image_operations.cc', 'native_theme.cc', 'png_decoder.cc', 'png_encoder.cc', 'point.cc', 'rect.cc', 'size.cc', + 'skia_utils.cc', ] if env['PLATFORM'] in ('posix', 'darwin'): @@ -40,6 +43,7 @@ if env['PLATFORM'] in ('posix', 'darwin'): to_be_ported_files = [ 'gdi_util.cc', 'native_theme.cc', + 'skia_utils.cc', ] for remove in to_be_ported_files: input_files.remove(remove) diff --git a/base/gfx/convolver.cc b/base/gfx/convolver.cc new file mode 100644 index 0000000..fd3503f --- /dev/null +++ b/base/gfx/convolver.cc @@ -0,0 +1,335 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include "base/basictypes.h" +#include "base/gfx/convolver.h" +#include "base/logging.h" + +namespace gfx { + +namespace { + +// Converts the argument to an 8-bit unsigned value by clamping to the range +// 0-255. +inline uint8 ClampTo8(int32 a) { + if (static_cast(a) < 256) + return a; // Avoid the extra check in the common case. + if (a < 0) + return 0; + return 255; +} + +// Stores a list of rows in a circular buffer. The usage is you write into it +// by calling AdvanceRow. It will keep track of which row in the buffer it +// should use next, and the total number of rows added. +class CircularRowBuffer { + public: + // The number of pixels in each row is given in |source_row_pixel_width|. + // The maximum number of rows needed in the buffer is |max_y_filter_size| + // (we only need to store enough rows for the biggest filter). + // + // We use the |first_input_row| to compute the coordinates of all of the + // following rows returned by Advance(). + CircularRowBuffer(int dest_row_pixel_width, int max_y_filter_size, + int first_input_row) + : row_byte_width_(dest_row_pixel_width * 4), + num_rows_(max_y_filter_size), + next_row_(0), + next_row_coordinate_(first_input_row) { + buffer_.resize(row_byte_width_ * max_y_filter_size); + row_addresses_.resize(num_rows_); + } + + // Moves to the next row in the buffer, returning a pointer to the beginning + // of it. + uint8* AdvanceRow() { + uint8* row = &buffer_[next_row_ * row_byte_width_]; + next_row_coordinate_++; + + // Set the pointer to the next row to use, wrapping around if necessary. + next_row_++; + if (next_row_ == num_rows_) + next_row_ = 0; + return row; + } + + // Returns a pointer to an "unrolled" array of rows. These rows will start + // at the y coordinate placed into |*first_row_index| and will continue in + // order for the maximum number of rows in this circular buffer. + // + // The |first_row_index_| may be negative. This means the circular buffer + // starts before the top of the image (it hasn't been filled yet). + uint8* const* GetRowAddresses(int* first_row_index) { + // Example for a 4-element circular buffer holding coords 6-9. + // Row 0 Coord 8 + // Row 1 Coord 9 + // Row 2 Coord 6 <- next_row_ = 2, next_row_coordinate_ = 10. + // Row 3 Coord 7 + // + // The "next" row is also the first (lowest) coordinate. This computation + // may yield a negative value, but that's OK, the math will work out + // since the user of this buffer will compute the offset relative + // to the first_row_index and the negative rows will never be used. + *first_row_index = next_row_coordinate_ - num_rows_; + + int cur_row = next_row_; + for (int i = 0; i < num_rows_; i++) { + row_addresses_[i] = &buffer_[cur_row * row_byte_width_]; + + // Advance to the next row, wrapping if necessary. + cur_row++; + if (cur_row == num_rows_) + cur_row = 0; + } + return &row_addresses_[0]; + } + + private: + // The buffer storing the rows. They are packed, each one row_byte_width_. + std::vector buffer_; + + // Number of bytes per row in the |buffer_|. + int row_byte_width_; + + // The number of rows available in the buffer. + int num_rows_; + + // The next row index we should write into. This wraps around as the + // circular buffer is used. + int next_row_; + + // The y coordinate of the |next_row_|. This is incremented each time a + // new row is appended and does not wrap. + int next_row_coordinate_; + + // Buffer used by GetRowAddresses(). + std::vector row_addresses_; +}; + +// Convolves horizontally along a single row. The row data is given in +// |src_data| and continues for the num_values() of the filter. +template +void ConvolveHorizontally(const uint8* src_data, + const ConvolusionFilter1D& filter, + unsigned char* out_row) { + // Loop over each pixel on this row in the output image. + int num_values = filter.num_values(); + for (int out_x = 0; out_x < num_values; out_x++) { + // Get the filter that determines the current output pixel. + int filter_offset, filter_length; + const int16* filter_values = + filter.FilterForValue(out_x, &filter_offset, &filter_length); + + // Compute the first pixel in this row that the filter affects. It will + // touch |filter_length| pixels (4 bytes each) after this. + const uint8* row_to_filter = &src_data[filter_offset * 4]; + + // Apply the filter to the row to get the destination pixel in |accum|. + int32 accum[4] = {0}; + for (int filter_x = 0; filter_x < filter_length; filter_x++) { + int16 cur_filter = filter_values[filter_x]; + accum[0] += cur_filter * row_to_filter[filter_x * 4 + 0]; + accum[1] += cur_filter * row_to_filter[filter_x * 4 + 1]; + accum[2] += cur_filter * row_to_filter[filter_x * 4 + 2]; + if (has_alpha) + accum[3] += cur_filter * row_to_filter[filter_x * 4 + 3]; + } + + // Bring this value back in range. All of the filter scaling factors + // are in fixed point with kShiftBits bits of fractional part. + accum[0] >>= ConvolusionFilter1D::kShiftBits; + accum[1] >>= ConvolusionFilter1D::kShiftBits; + accum[2] >>= ConvolusionFilter1D::kShiftBits; + if (has_alpha) + accum[3] >>= ConvolusionFilter1D::kShiftBits; + + // Store the new pixel. + out_row[out_x * 4 + 0] = ClampTo8(accum[0]); + out_row[out_x * 4 + 1] = ClampTo8(accum[1]); + out_row[out_x * 4 + 2] = ClampTo8(accum[2]); + if (has_alpha) + out_row[out_x * 4 + 3] = ClampTo8(accum[3]); + } +} + +// Does vertical convolusion to produce one output row. The filter values and +// length are given in the first two parameters. These are applied to each +// of the rows pointed to in the |source_data_rows| array, with each row +// being |pixel_width| wide. +// +// The output must have room for |pixel_width * 4| bytes. +template +void ConvolveVertically(const int16* filter_values, + int filter_length, + uint8* const* source_data_rows, + int pixel_width, + uint8* out_row) { + // We go through each column in the output and do a vertical convolusion, + // generating one output pixel each time. + for (int out_x = 0; out_x < pixel_width; out_x++) { + // Compute the number of bytes over in each row that the current column + // we're convolving starts at. The pixel will cover the next 4 bytes. + int byte_offset = out_x * 4; + + // Apply the filter to one column of pixels. + int32 accum[4] = {0}; + for (int filter_y = 0; filter_y < filter_length; filter_y++) { + int16 cur_filter = filter_values[filter_y]; + accum[0] += cur_filter * source_data_rows[filter_y][byte_offset + 0]; + accum[1] += cur_filter * source_data_rows[filter_y][byte_offset + 1]; + accum[2] += cur_filter * source_data_rows[filter_y][byte_offset + 2]; + if (has_alpha) + accum[3] += cur_filter * source_data_rows[filter_y][byte_offset + 3]; + } + + // Bring this value back in range. All of the filter scaling factors + // are in fixed point with kShiftBits bits of precision. + accum[0] >>= ConvolusionFilter1D::kShiftBits; + accum[1] >>= ConvolusionFilter1D::kShiftBits; + accum[2] >>= ConvolusionFilter1D::kShiftBits; + if (has_alpha) + accum[3] >>= ConvolusionFilter1D::kShiftBits; + + // Store the new pixel. + out_row[byte_offset + 0] = ClampTo8(accum[0]); + out_row[byte_offset + 1] = ClampTo8(accum[1]); + out_row[byte_offset + 2] = ClampTo8(accum[2]); + if (has_alpha) { + uint8 alpha = ClampTo8(accum[3]); + + // Make sure the alpha channel doesn't come out larger than any of the + // color channels. We use premultipled alpha channels, so this should + // never happen, but rounding errors will cause this from time to time. + // These "impossible" colors will cause overflows (and hence random pixel + // values) when the resulting bitmap is drawn to the screen. + // + // We only need to do this when generating the final output row (here). + int max_color_channel = std::max(out_row[byte_offset + 0], + std::max(out_row[byte_offset + 1], out_row[byte_offset + 2])); + if (alpha < max_color_channel) + out_row[byte_offset + 3] = max_color_channel; + else + out_row[byte_offset + 3] = alpha; + } else { + // No alpha channel, the image is opaque. + out_row[byte_offset + 3] = 0xff; + } + } +} + +} // namespace + +// ConvolusionFilter1D --------------------------------------------------------- + +void ConvolusionFilter1D::AddFilter(int filter_offset, + const float* filter_values, + int filter_length) { + FilterInstance instance; + instance.data_location = static_cast(filter_values_.size()); + instance.offset = filter_offset; + instance.length = filter_length; + filters_.push_back(instance); + + DCHECK(filter_length > 0); + for (int i = 0; i < filter_length; i++) + filter_values_.push_back(FloatToFixed(filter_values[i])); + + max_filter_ = std::max(max_filter_, filter_length); +} + +void ConvolusionFilter1D::AddFilter(int filter_offset, + const int16* filter_values, + int filter_length) { + FilterInstance instance; + instance.data_location = static_cast(filter_values_.size()); + instance.offset = filter_offset; + instance.length = filter_length; + filters_.push_back(instance); + + DCHECK(filter_length > 0); + for (int i = 0; i < filter_length; i++) + filter_values_.push_back(filter_values[i]); + + max_filter_ = std::max(max_filter_, filter_length); +} + +// BGRAConvolve2D ------------------------------------------------------------- + +void BGRAConvolve2D(const uint8* source_data, + int source_byte_row_stride, + bool source_has_alpha, + const ConvolusionFilter1D& filter_x, + const ConvolusionFilter1D& filter_y, + uint8* output) { + int max_y_filter_size = filter_y.max_filter(); + + // The next row in the input that we will generate a horizontally + // convolved row for. If the filter doesn't start at the beginning of the + // image (this is the case when we are only resizing a subset), then we + // don't want to generate any output rows before that. Compute the starting + // row for convolusion as the first pixel for the first vertical filter. + int filter_offset, filter_length; + const int16* filter_values = + filter_y.FilterForValue(0, &filter_offset, &filter_length); + int next_x_row = filter_offset; + + // We loop over each row in the input doing a horizontal convolusion. This + // will result in a horizontally convolved image. We write the results into + // a circular buffer of convolved rows and do vertical convolusion as rows + // are available. This prevents us from having to store the entire + // intermediate image and helps cache coherency. + CircularRowBuffer row_buffer(filter_x.num_values(), max_y_filter_size, + filter_offset); + + // Loop over every possible output row, processing just enough horizontal + // convolusions to run each subsequent vertical convolusion. + int output_row_byte_width = filter_x.num_values() * 4; + int num_output_rows = filter_y.num_values(); + for (int out_y = 0; out_y < num_output_rows; out_y++) { + filter_values = filter_y.FilterForValue(out_y, + &filter_offset, &filter_length); + + // Generate output rows until we have enough to run the current filter. + while (next_x_row < filter_offset + filter_length) { + if (source_has_alpha) { + ConvolveHorizontally( + &source_data[next_x_row * source_byte_row_stride], + filter_x, row_buffer.AdvanceRow()); + } else { + ConvolveHorizontally( + &source_data[next_x_row * source_byte_row_stride], + filter_x, row_buffer.AdvanceRow()); + } + next_x_row++; + } + + // Compute where in the output image this row of final data will go. + uint8* cur_output_row = &output[out_y * output_row_byte_width]; + + // Get the list of rows that the circular buffer has, in order. + int first_row_in_circular_buffer; + uint8* const* rows_to_convolve = + row_buffer.GetRowAddresses(&first_row_in_circular_buffer); + + // Now compute the start of the subset of those rows that the filter + // needs. + uint8* const* first_row_for_filter = + &rows_to_convolve[filter_offset - first_row_in_circular_buffer]; + + if (source_has_alpha) { + ConvolveVertically(filter_values, filter_length, + first_row_for_filter, + filter_x.num_values(), cur_output_row); + } else { + ConvolveVertically(filter_values, filter_length, + first_row_for_filter, + filter_x.num_values(), cur_output_row); + } + } +} + +} // namespace gfx + diff --git a/base/gfx/convolver.h b/base/gfx/convolver.h new file mode 100644 index 0000000..12c9228 --- /dev/null +++ b/base/gfx/convolver.h @@ -0,0 +1,137 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_GFX_CONVOLVER_H__ +#define BASE_GFX_CONVOLVER_H__ + +#include + +#include "base/basictypes.h" + +// avoid confusion with Mac OS X's math library (Carbon) +#if defined(OS_MACOSX) +#undef FloatToFixed +#endif + +namespace gfx { + +// Represents a filter in one dimension. Each output pixel has one entry in this +// object for the filter values contributing to it. You build up the filter +// list by calling AddFilter for each output pixel (in order). +// +// We do 2-dimensional convolusion by first convolving each row by one +// ConvolusionFilter1D, then convolving each column by another one. +// +// Entries are stored in fixed point, shifted left by kShiftBits. +class ConvolusionFilter1D { + public: + // The number of bits that fixed point values are shifted by. + enum { kShiftBits = 14 }; + + ConvolusionFilter1D() : max_filter_(0) { + } + + // Convert between floating point and our fixed point representation. + static inline int16 FloatToFixed(float f) { + return static_cast(f * (1 << kShiftBits)); + } + static inline unsigned char FixedToChar(int16 x) { + return static_cast(x >> kShiftBits); + } + + // Returns the maximum pixel span of a filter. + int max_filter() const { return max_filter_; } + + // Returns the number of filters in this filter. This is the dimension of the + // output image. + int num_values() const { return static_cast(filters_.size()); } + + // Appends the given list of scaling values for generating a given output + // pixel. |filter_offset| is the distance from the edge of the image to where + // the scaling factors start. The scaling factors apply to the source pixels + // starting from this position, and going for the next |filter_length| pixels. + // + // You will probably want to make sure your input is normalized (that is, + // all entries in |filter_values| sub to one) to prevent affecting the overall + // brighness of the image. + // + // The filter_length must be > 0. + // + // This version will automatically convert your input to fixed point. + void AddFilter(int filter_offset, + const float* filter_values, + int filter_length); + + // Same as the above version, but the input is already fixed point. + void AddFilter(int filter_offset, + const int16* filter_values, + int filter_length); + + // Retrieves a filter for the given |value_offset|, a position in the output + // image in the direction we're convolving. The offset and length of the + // filter values are put into the corresponding out arguments (see AddFilter + // above for what these mean), and a pointer to the first scaling factor is + // returned. There will be |filter_length| values in this array. + inline const int16* FilterForValue(int value_offset, + int* filter_offset, + int* filter_length) const { + const FilterInstance& filter = filters_[value_offset]; + *filter_offset = filter.offset; + *filter_length = filter.length; + return &filter_values_[filter.data_location]; + } + + private: + struct FilterInstance { + // Offset within filter_values for this instance of the filter. + int data_location; + + // Distance from the left of the filter to the center. IN PIXELS + int offset; + + // Number of values in this filter instance. + int length; + }; + + // Stores the information for each filter added to this class. + std::vector filters_; + + // We store all the filter values in this flat list, indexed by + // |FilterInstance.data_location| to avoid the mallocs required for storing + // each one separately. + std::vector filter_values_; + + // The maximum size of any filter we've added. + int max_filter_; +}; + +// Does a two-dimensional convolusion on the given source image. +// +// It is assumed the source pixel offsets referenced in the input filters +// reference only valid pixels, so the source image size is not required. Each +// row of the source image starts |source_byte_row_stride| after the previous +// one (this allows you to have rows with some padding at the end). +// +// The result will be put into the given output buffer. The destination image +// size will be xfilter.num_values() * yfilter.num_values() pixels. It will be +// in rows of exactly xfilter.num_values() * 4 bytes. +// +// |source_has_alpha| is a hint that allows us to avoid doing computations on +// the alpha channel if the image is opaque. If you don't know, set this to +// true and it will work properly, but setting this to false will be a few +// percent faster if you know the image is opaque. +// +// The layout in memory is assumed to be 4-bytes per pixel in B-G-R-A order +// (this is ARGB when loaded into 32-bit words on a little-endian machine). +void BGRAConvolve2D(const uint8* source_data, + int source_byte_row_stride, + bool source_has_alpha, + const ConvolusionFilter1D& xfilter, + const ConvolusionFilter1D& yfilter, + uint8* output); + +} // namespace gfx + +#endif // BASE_GFX_CONVOLVER_H__ + diff --git a/base/gfx/convolver_unittest.cc b/base/gfx/convolver_unittest.cc new file mode 100644 index 0000000..0a30a6b --- /dev/null +++ b/base/gfx/convolver_unittest.cc @@ -0,0 +1,127 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include +#include + +#include "base/gfx/convolver.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gfx { + +namespace { + +// Fills the given filter with impulse functions for the range 0->num_entries. + void FillImpulseFilter(int num_entries, ConvolusionFilter1D* filter) { + float one = 1.0f; + for (int i = 0; i < num_entries; i++) + filter->AddFilter(i, &one, 1); +} + +// Filters the given input with the impulse function, and verifies that it +// does not change. +void TestImpulseConvolusion(const unsigned char* data, int width, int height) { + int byte_count = width * height * 4; + + ConvolusionFilter1D filter_x; + FillImpulseFilter(width, &filter_x); + + ConvolusionFilter1D filter_y; + FillImpulseFilter(height, &filter_y); + + std::vector output; + output.resize(byte_count); + BGRAConvolve2D(data, width * 4, true, filter_x, filter_y, &output[0]); + + // Output should exactly match input. + EXPECT_EQ(0, memcmp(data, &output[0], byte_count)); +} + +// Fills the destination filter with a box filter averaging every two pixels +// to produce the output. +void FillBoxFilter(int size, ConvolusionFilter1D* filter) { + const float box[2] = { 0.5, 0.5 }; + for (int i = 0; i < size; i++) + filter->AddFilter(i * 2, box, 2); +} + +} // namespace + +// Tests that each pixel, when set and run through the impulse filter, does +// not change. +TEST(Convolver, Impulse) { + // We pick an "odd" size that is not likely to fit on any boundaries so that + // we can see if all the widths and paddings are handled properly. + int width = 15; + int height = 31; + int byte_count = width * height * 4; + std::vector input; + input.resize(byte_count); + + unsigned char* input_ptr = &input[0]; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + for (int channel = 0; channel < 3; channel++) { + memset(input_ptr, 0, byte_count); + input_ptr[(y * width + x) * 4 + channel] = 0xff; + // Always set the alpha channel or it will attempt to "fix" it for us. + input_ptr[(y * width + x) * 4 + 3] = 0xff; + TestImpulseConvolusion(input_ptr, width, height); + } + } + } +} + +// Tests that using a box filter to halve an image results in every square of 4 +// pixels in the original get averaged to a pixel in the output. +TEST(Convolver, Halve) { + static const int kSize = 16; + + int src_width = kSize; + int src_height = kSize; + int src_row_stride = src_width * 4; + int src_byte_count = src_row_stride * src_height; + std::vector input; + input.resize(src_byte_count); + + int dest_width = src_width / 2; + int dest_height = src_height / 2; + int dest_byte_count = dest_width * dest_height * 4; + std::vector output; + output.resize(dest_byte_count); + + // First fill the array with a bunch of random data. + srand(static_cast(time(NULL))); + for (int i = 0; i < src_byte_count; i++) + input[i] = rand() * 255 / RAND_MAX; + + // Compute the filters. + ConvolusionFilter1D filter_x, filter_y; + FillBoxFilter(dest_width, &filter_x); + FillBoxFilter(dest_height, &filter_y); + + // Do the convolusion. + BGRAConvolve2D(&input[0], src_width, true, filter_x, filter_y, &output[0]); + + // Compute the expected results and check, allowing for a small difference + // to account for rounding errors. + for (int y = 0; y < dest_height; y++) { + for (int x = 0; x < dest_width; x++) { + for (int channel = 0; channel < 4; channel++) { + int src_offset = (y * 2 * src_row_stride + x * 2 * 4) + channel; + int value = input[src_offset] + // Top left source pixel. + input[src_offset + 4] + // Top right source pixel. + input[src_offset + src_row_stride] + // Lower left. + input[src_offset + src_row_stride + 4]; // Lower right. + value /= 4; // Average. + int difference = value - output[(y * dest_width + x) * 4 + channel]; + EXPECT_TRUE(difference >= -1 || difference <= 1); + } + } + } +} + +} // namespace gfx + diff --git a/base/gfx/image_operations.cc b/base/gfx/image_operations.cc new file mode 100644 index 0000000..a60d19e --- /dev/null +++ b/base/gfx/image_operations.cc @@ -0,0 +1,362 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#define _USE_MATH_DEFINES +#include +#include +#include + +#include "base/gfx/image_operations.h" + +#include "base/gfx/convolver.h" +#include "base/gfx/rect.h" +#include "base/gfx/size.h" +#include "base/logging.h" +#include "base/stack_container.h" +#include "SkBitmap.h" + +namespace gfx { + +namespace { + +// Returns the ceiling/floor as an integer. +inline int CeilInt(float val) { + return static_cast(ceil(val)); +} +inline int FloorInt(float val) { + return static_cast(floor(val)); +} + +// Filter function computation ------------------------------------------------- + +// Evaluates the box filter, which goes from -0.5 to +0.5. +float EvalBox(float x) { + return (x >= -0.5f && x < 0.5f) ? 1.0f : 0.0f; +} + +// Evaluates the Lanczos filter of the given filter size window for the given +// position. +// +// |filter_size| is the width of the filter (the "window"), outside of which +// the value of the function is 0. Inside of the window, the value is the +// normalized sinc function: +// lanczos(x) = sinc(x) * sinc(x / filter_size); +// where +// sinc(x) = sin(pi*x) / (pi*x); +float EvalLanczos(int filter_size, float x) { + if (x <= -filter_size || x >= filter_size) + return 0.0f; // Outside of the window. + if (x > -std::numeric_limits::epsilon() && + x < std::numeric_limits::epsilon()) + return 1.0f; // Special case the discontinuity at the origin. + float xpi = x * static_cast(M_PI); + return (sin(xpi) / xpi) * // sinc(x) + sin(xpi / filter_size) / (xpi / filter_size); // sinc(x/filter_size) +} + +// ResizeFilter ---------------------------------------------------------------- + +// Encapsulates computation and storage of the filters required for one complete +// resize operation. +class ResizeFilter { + public: + ResizeFilter(ImageOperations::ResizeMethod method, + const Size& src_full_size, + const Size& dest_size, + const Rect& dest_subset); + + // Returns the bounds in the input bitmap of data that is used in the output. + // The filter offsets are within this rectangle. + const Rect& src_depend() { return src_depend_; } + + // Returns the filled filter values. + const ConvolusionFilter1D& x_filter() { return x_filter_; } + const ConvolusionFilter1D& y_filter() { return y_filter_; } + + private: + // Returns the number of pixels that the filer spans, in filter space (the + // destination image). + float GetFilterSupport(float scale) { + switch (method_) { + case ImageOperations::RESIZE_BOX: + // The box filter just scales with the image scaling. + return 0.5f; // Only want one side of the filter = /2. + case ImageOperations::RESIZE_LANCZOS3: + // The lanczos filter takes as much space in the source image in + // each direction as the size of the window = 3 for Lanczos3. + return 3.0f; + default: + NOTREACHED(); + return 1.0f; + } + } + + // Computes one set of filters either horizontally or vertically. The caller + // will specify the "min" and "max" rather than the bottom/top and + // right/bottom so that the same code can be re-used in each dimension. + // + // |src_depend_lo| and |src_depend_size| gives the range for the source + // depend rectangle (horizontally or vertically at the caller's discretion + // -- see above for what this means). + // + // Likewise, the range of destination values to compute and the scale factor + // for the transform is also specified. + void ComputeFilters(int src_size, + int dest_subset_lo, int dest_subset_size, + float scale, float src_support, + ConvolusionFilter1D* output); + + // Computes the filter value given the coordinate in filter space. + inline float ComputeFilter(float pos) { + switch (method_) { + case ImageOperations::RESIZE_BOX: + return EvalBox(pos); + case ImageOperations::RESIZE_LANCZOS3: + return EvalLanczos(3, pos); + default: + NOTREACHED(); + return 0; + } + } + + ImageOperations::ResizeMethod method_; + + // Subset of source the filters will touch. + Rect src_depend_; + + // Size of the filter support on one side only in the destination space. + // See GetFilterSupport. + float x_filter_support_; + float y_filter_support_; + + // Subset of scaled destination bitmap to compute. + Rect out_bounds_; + + ConvolusionFilter1D x_filter_; + ConvolusionFilter1D y_filter_; + + DISALLOW_EVIL_CONSTRUCTORS(ResizeFilter); +}; + +ResizeFilter::ResizeFilter(ImageOperations::ResizeMethod method, + const Size& src_full_size, + const Size& dest_size, + const Rect& dest_subset) + : method_(method), + out_bounds_(dest_subset) { + float scale_x = static_cast(dest_size.width()) / + static_cast(src_full_size.width()); + float scale_y = static_cast(dest_size.height()) / + static_cast(src_full_size.height()); + + x_filter_support_ = GetFilterSupport(scale_x); + y_filter_support_ = GetFilterSupport(scale_y); + + gfx::Rect src_full(0, 0, src_full_size.width(), src_full_size.height()); + gfx::Rect dest_full(0, 0, + static_cast(src_full_size.width() * scale_x + 0.5), + static_cast(src_full_size.height() * scale_y + 0.5)); + + // Support of the filter in source space. + float src_x_support = x_filter_support_ / scale_x; + float src_y_support = y_filter_support_ / scale_y; + + ComputeFilters(src_full_size.width(), dest_subset.x(), dest_subset.width(), + scale_x, src_x_support, &x_filter_); + ComputeFilters(src_full_size.height(), dest_subset.y(), dest_subset.height(), + scale_y, src_y_support, &y_filter_); +} + +void ResizeFilter::ComputeFilters(int src_size, + int dest_subset_lo, int dest_subset_size, + float scale, float src_support, + ConvolusionFilter1D* output) { + int dest_subset_hi = dest_subset_lo + dest_subset_size; // [lo, hi) + + // When we're doing a magnification, the scale will be larger than one. This + // means the destination pixels are much smaller than the source pixels, and + // that the range covered by the filter won't necessarily cover any source + // pixel boundaries. Therefore, we use these clamped values (max of 1) for + // some computations. + float clamped_scale = std::min(1.0f, scale); + + // Speed up the divisions below by turning them into multiplies. + float inv_scale = 1.0f / scale; + + StackVector filter_values; + StackVector fixed_filter_values; + + // Loop over all pixels in the output range. We will generate one set of + // filter values for each one. Those values will tell us how to blend the + // source pixels to compute the destination pixel. + for (int dest_subset_i = dest_subset_lo; dest_subset_i < dest_subset_hi; + dest_subset_i++) { + // Reset the arrays. We don't declare them inside so they can re-use the + // same malloc-ed buffer. + filter_values->clear(); + fixed_filter_values->clear(); + + // This is the pixel in the source directly under the pixel in the dest. + float src_pixel = dest_subset_i * inv_scale; + + // Compute the (inclusive) range of source pixels the filter covers. + int src_begin = std::max(0, FloorInt(src_pixel - src_support)); + int src_end = std::min(src_size - 1, CeilInt(src_pixel + src_support)); + + // Compute the unnormalized filter value at each location of the source + // it covers. + float filter_sum = 0.0f; // Sub of the filter values for normalizing. + for (int cur_filter_pixel = src_begin; cur_filter_pixel <= src_end; + cur_filter_pixel++) { + // Distance from the center of the filter, this is the filter coordinate + // in source space. + float src_filter_pos = cur_filter_pixel - src_pixel; + + // Since the filter really exists in dest space, map it there. + float dest_filter_pos = src_filter_pos * clamped_scale; + + // Compute the filter value at that location. + float filter_value = ComputeFilter(dest_filter_pos); + filter_values->push_back(filter_value); + + filter_sum += filter_value; + } + DCHECK(!filter_values->empty()) << "We should always get a filter!"; + + // The filter must be normalized so that we don't affect the brightness of + // the image. Convert to normalized fixed point. + int16 fixed_sum = 0; + for (size_t i = 0; i < filter_values->size(); i++) { + int16 cur_fixed = output->FloatToFixed(filter_values[i] / filter_sum); + fixed_sum += cur_fixed; + fixed_filter_values->push_back(cur_fixed); + } + + // The conversion to fixed point will leave some rounding errors, which + // we add back in to avoid affecting the brightness of the image. We + // arbitrarily add this to the center of the filter array (this won't always + // be the center of the filter function since it could get clipped on the + // edges, but it doesn't matter enough to worry about that case). + int16 leftovers = output->FloatToFixed(1.0f) - fixed_sum; + fixed_filter_values[fixed_filter_values->size() / 2] += leftovers; + + // Now it's ready to go. + output->AddFilter(src_begin, &fixed_filter_values[0], + static_cast(fixed_filter_values->size())); + } +} + +} // namespace + +// Resize ---------------------------------------------------------------------- + +// static +SkBitmap ImageOperations::Resize(const SkBitmap& source, + ResizeMethod method, + const Size& dest_size, + const Rect& dest_subset) { + DCHECK(Rect(dest_size.width(), dest_size.height()).Contains(dest_subset)) << + "The supplied subset does not fall within the destination image."; + + // If the size of source or destination is 0, i.e. 0x0, 0xN or Nx0, just + // return empty + if (source.width() < 1 || source.height() < 1 || + dest_size.width() < 1 || dest_size.height() < 1) + return SkBitmap(); + + SkAutoLockPixels locker(source); + + ResizeFilter filter(method, Size(source.width(), source.height()), + dest_size, dest_subset); + + // Get a source bitmap encompassing this touched area. We construct the + // offsets and row strides such that it looks like a new bitmap, while + // referring to the old data. + const uint8* source_subset = + reinterpret_cast(source.getPixels()); + + // Convolve into the result. + SkBitmap result; + result.setConfig(SkBitmap::kARGB_8888_Config, + dest_subset.width(), dest_subset.height()); + result.allocPixels(); + BGRAConvolve2D(source_subset, static_cast(source.rowBytes()), + !source.isOpaque(), filter.x_filter(), filter.y_filter(), + static_cast(result.getPixels())); + + // Preserve the "opaque" flag for use as an optimization later. + result.setIsOpaque(source.isOpaque()); + + return result; +} + +// static +SkBitmap ImageOperations::Resize(const SkBitmap& source, + ResizeMethod method, + const Size& dest_size) { + Rect dest_subset(0, 0, dest_size.width(), dest_size.height()); + return Resize(source, method, dest_size, dest_subset); +} + +// static +SkBitmap ImageOperations::CreateBlendedBitmap(const SkBitmap& first, + const SkBitmap& second, + double alpha) { + DCHECK(alpha <= 1 && alpha >= 0); + DCHECK(first.width() == second.width()); + DCHECK(first.height() == second.height()); + DCHECK(first.bytesPerPixel() == second.bytesPerPixel()); + DCHECK(first.config() == SkBitmap::kARGB_8888_Config); + + // Optimize for case where we won't need to blend anything. + static const double alpha_min = 1.0 / 255; + static const double alpha_max = 254.0 / 255; + if (alpha < alpha_min) { + return first; + } else if (alpha > alpha_max) { + return second; + } + + SkAutoLockPixels lock_first(first); + SkAutoLockPixels lock_second(second); + + SkBitmap blended; + blended.setConfig(SkBitmap::kARGB_8888_Config, first.width(), + first.height(), 0); + blended.allocPixels(); + blended.eraseARGB(0, 0, 0, 0); + + double first_alpha = 1 - alpha; + + for (int y = 0; y < first.height(); y++) { + uint32* first_row = first.getAddr32(0, y); + uint32* second_row = second.getAddr32(0, y); + uint32* dst_row = blended.getAddr32(0, y); + + for (int x = 0; x < first.width(); x++) { + uint32 first_pixel = first_row[x]; + uint32 second_pixel = second_row[x]; + + int a = static_cast( + SkColorGetA(first_pixel) * first_alpha + + SkColorGetA(second_pixel) * alpha); + int r = static_cast( + SkColorGetR(first_pixel) * first_alpha + + SkColorGetR(second_pixel) * alpha); + int g = static_cast( + SkColorGetG(first_pixel) * first_alpha + + SkColorGetG(second_pixel) * alpha); + int b = static_cast( + SkColorGetB(first_pixel) * first_alpha + + SkColorGetB(second_pixel) * alpha); + + dst_row[x] = SkColorSetARGB(a, r, g, b); + } + } + + return blended; +} + +} // namespace gfx + diff --git a/base/gfx/image_operations.h b/base/gfx/image_operations.h new file mode 100644 index 0000000..826e651 --- /dev/null +++ b/base/gfx/image_operations.h @@ -0,0 +1,63 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_GFX_IMAGE_OPERATIONS_H__ +#define BASE_GFX_IMAGE_OPERATIONS_H__ + +#include "base/basictypes.h" +#include "base/gfx/rect.h" + +class SkBitmap; + +namespace gfx { + +class ImageOperations { + public: + enum ResizeMethod { + // Box filter. This is a weighted average of all of the pixels touching + // the destination pixel. For enlargement, this is nearest neighbor. + // + // You probably don't want this, it is here for testing since it is easy to + // compute. Use RESIZE_LANCZOS3 instead. + RESIZE_BOX, + + // 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, + }; + + // Resizes the given source bitmap using the specified resize method, so that + // the entire image is (dest_size) big. The dest_subset is the rectangle in + // this destination image that should actually be returned. + // + // The output image will be (dest_subset.width(), dest_subset.height()). This + // will save work if you do not need the entire bitmap. + // + // The destination subset must be smaller than the destination image. + static SkBitmap Resize(const SkBitmap& source, + ResizeMethod method, + const Size& dest_size, + const Rect& dest_subset); + + // Alternate version for resizing and returning the entire bitmap rather than + // a subset. + static SkBitmap Resize(const SkBitmap& source, + ResizeMethod method, + const Size& dest_size); + + + // Create a bitmap that is a blend of two others. The alpha argument + // specifies the opacity of the second bitmap. The provided bitmaps must + // use have the kARGB_8888_Config config and be of equal dimensions. + static SkBitmap CreateBlendedBitmap(const SkBitmap& first, + const SkBitmap& second, + double alpha); + private: + ImageOperations(); // Class for scoping only. +}; + +} // namespace gfx + +#endif // BASE_GFX_IMAGE_OPERATIONS_H__ + diff --git a/base/gfx/image_operations_unittest.cc b/base/gfx/image_operations_unittest.cc new file mode 100644 index 0000000..a15e648 --- /dev/null +++ b/base/gfx/image_operations_unittest.cc @@ -0,0 +1,148 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include "base/gfx/image_operations.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "SkBitmap.h" + +namespace { + +// Computes the average pixel value for the given range, inclusive. +uint32_t AveragePixel(const SkBitmap& bmp, + int x_min, int x_max, + int y_min, int y_max) { + float accum[4] = {0, 0, 0, 0}; + int count = 0; + for (int y = y_min; y <= y_max; y++) { + for (int x = x_min; x <= x_max; x++) { + uint32_t cur = *bmp.getAddr32(x, y); + accum[0] += SkColorGetB(cur); + accum[1] += SkColorGetG(cur); + accum[2] += SkColorGetR(cur); + accum[3] += SkColorGetA(cur); + count++; + } + } + + return SkColorSetARGB(static_cast(accum[3] / count), + static_cast(accum[2] / count), + static_cast(accum[1] / count), + static_cast(accum[0] / count)); +} + +// Returns true if each channel of the given two colors are "close." This is +// used for comparing colors where rounding errors may cause off-by-one. +bool ColorsClose(uint32_t a, uint32_t b) { + return abs(static_cast(SkColorGetB(a) - SkColorGetB(b))) < 2 && + abs(static_cast(SkColorGetG(a) - SkColorGetG(b))) < 2 && + abs(static_cast(SkColorGetR(a) - SkColorGetR(b))) < 2 && + abs(static_cast(SkColorGetA(a) - SkColorGetA(b))) < 2; +} + +void FillDataToBitmap(int w, int h, SkBitmap* bmp) { + bmp->setConfig(SkBitmap::kARGB_8888_Config, w, h); + bmp->allocPixels(); + + unsigned char* src_data = + reinterpret_cast(bmp->getAddr32(0, 0)); + for (int i = 0; i < w * h; i++) { + src_data[i * 4 + 0] = static_cast(i % 255); + src_data[i * 4 + 1] = static_cast(i % 255); + src_data[i * 4 + 2] = static_cast(i % 255); + src_data[i * 4 + 3] = static_cast(i % 255); + } +} + +} // namespace + +// Makes the bitmap 50% the size as the original using a box filter. This is +// an easy operation that we can check the results for manually. +TEST(ImageOperations, Halve) { + // Make our source bitmap. + int src_w = 30, src_h = 38; + SkBitmap src; + FillDataToBitmap(src_w, src_h, &src); + + // Do a halving of the full bitmap. + SkBitmap actual_results = gfx::ImageOperations::Resize( + src, gfx::ImageOperations::RESIZE_BOX, gfx::Size(src_w / 2, src_h / 2)); + ASSERT_EQ(src_w / 2, actual_results.width()); + ASSERT_EQ(src_h / 2, actual_results.height()); + + // Compute the expected values & compare. + SkAutoLockPixels lock(actual_results); + for (int y = 0; y < actual_results.height(); y++) { + for (int x = 0; x < actual_results.width(); x++) { + int first_x = std::max(0, x * 2 - 1); + int last_x = std::min(src_w - 1, x * 2); + + int first_y = std::max(0, y * 2 - 1); + int last_y = std::min(src_h - 1, y * 2); + + uint32_t expected_color = AveragePixel(src, + first_x, last_x, first_y, last_y); + EXPECT_TRUE(ColorsClose(expected_color, *actual_results.getAddr32(x, y))); + } + } +} + +TEST(ImageOperations, HalveSubset) { + // Make our source bitmap. + int src_w = 16, src_h = 34; + SkBitmap src; + FillDataToBitmap(src_w, src_h, &src); + + // Do a halving of the full bitmap. + SkBitmap full_results = gfx::ImageOperations::Resize( + src, gfx::ImageOperations::RESIZE_BOX, gfx::Size(src_w / 2, src_h / 2)); + ASSERT_EQ(src_w / 2, full_results.width()); + ASSERT_EQ(src_h / 2, full_results.height()); + + // Now do a halving of a a subset, recall the destination subset is in the + // destination coordinate system (max = half of the original image size). + gfx::Rect subset_rect(2, 3, 3, 6); + SkBitmap subset_results = gfx::ImageOperations::Resize( + src, gfx::ImageOperations::RESIZE_BOX, + gfx::Size(src_w / 2, src_h / 2), subset_rect); + ASSERT_EQ(subset_rect.width(), subset_results.width()); + ASSERT_EQ(subset_rect.height(), subset_results.height()); + + // The computed subset and the corresponding subset of the original image + // should be the same. + SkAutoLockPixels full_lock(full_results); + SkAutoLockPixels subset_lock(subset_results); + for (int y = 0; y < subset_rect.height(); y++) { + for (int x = 0; x < subset_rect.width(); x++) { + ASSERT_EQ( + *full_results.getAddr32(x + subset_rect.x(), y + subset_rect.y()), + *subset_results.getAddr32(x, y)); + } + } +} + +// Resamples an iamge to the same image, it should give almost the same result. +TEST(ImageOperations, ResampleToSame) { + // Make our source bitmap. + int src_w = 16, src_h = 34; + SkBitmap src; + FillDataToBitmap(src_w, src_h, &src); + + // Do a resize of the full bitmap to the same size. The lanczos filter is good + // enough that we should get exactly the same image for output. + SkBitmap results = gfx::ImageOperations::Resize( + src, gfx::ImageOperations::RESIZE_LANCZOS3, gfx::Size(src_w, src_h)); + ASSERT_EQ(src_w, results.width()); + ASSERT_EQ(src_h, results.height()); + + SkAutoLockPixels src_lock(src); + SkAutoLockPixels results_lock(results); + for (int y = 0; y < src_h; y++) { + for (int x = 0; x < src_w; x++) { + EXPECT_EQ(*src.getAddr32(x, y), *results.getAddr32(x, y)); + } + } +} + diff --git a/base/gfx/img_resize_perftest.cc b/base/gfx/img_resize_perftest.cc new file mode 100644 index 0000000..6a4b070 --- /dev/null +++ b/base/gfx/img_resize_perftest.cc @@ -0,0 +1,70 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +#include "base/perftimer.h" +#include "base/gfx/convolver.h" +#include "base/gfx/image_operations.h" +#include "base/gfx/image_resizer.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +void FillRandomData(char* dest, int byte_count) { + srand(static_cast(time(NULL))); + for (int i = 0; i < byte_count; i++) + dest[i] = rand() * 255 / RAND_MAX; +} + +} // namespace + +// Old code gives [1521, 1519]ms for this, 4000x4000 -> 2100x2100 lanczos8 + +TEST(ImageResizePerf, BigFilter) { + static const int kSrcWidth = 4000; + static const int kSrcHeight = 4000; + static const int kSrcByteSize = kSrcWidth * kSrcHeight * 4; + + SkBitmap src_bmp; + src_bmp.setConfig(SkBitmap::kARGB_8888_Config, kSrcWidth, kSrcHeight); + src_bmp.allocPixels(); + FillRandomData(reinterpret_cast(src_bmp.getAddr32(0, 0)), + kSrcByteSize); + + // Make the dest size > 1/2 so the 50% optimization doesn't kick in. + static const int kDestWidth = 1400; + static const int kDestHeight = 1400; + + PerfTimeLogger resize_timer("resize"); + gfx::ImageResizer resizer(gfx::ImageResizer::LANCZOS3); + SkBitmap dest = resizer.Resize(src_bmp, kDestWidth, kDestHeight); +} + +// The original image filter we were using took 523ms for this test, while this +// one takes 857ms. +// TODO(brettw) make this at least 64% faster. +TEST(ImageOperationPerf, BigFilter) { + static const int kSrcWidth = 4000; + static const int kSrcHeight = 4000; + static const int kSrcByteSize = kSrcWidth * kSrcHeight * 4; + + SkBitmap src_bmp; + src_bmp.setConfig(SkBitmap::kARGB_8888_Config, kSrcWidth, kSrcHeight); + src_bmp.allocPixels(); + src_bmp.setIsOpaque(true); + FillRandomData(reinterpret_cast(src_bmp.getAddr32(0, 0)), + kSrcByteSize); + + // Make the dest size > 1/2 so the 50% optimization doesn't kick in. + static const int kDestWidth = 1400; + static const int kDestHeight = 1400; + + PerfTimeLogger resize_timer("resize"); + SkBitmap dest = gfx::ImageOperations::Resize(src_bmp, + gfx::ImageOperations::RESIZE_LANCZOS3, (float)kDestWidth / (float)kSrcWidth, + (float)kDestHeight / (float)kSrcHeight); +} + diff --git a/base/gfx/native_theme.cc b/base/gfx/native_theme.cc index 8c7914d..71289d8 100644 --- a/base/gfx/native_theme.cc +++ b/base/gfx/native_theme.cc @@ -10,11 +10,11 @@ #include #include "base/gfx/gdi_util.h" +#include "base/gfx/skia_utils.h" #include "base/gfx/rect.h" #include "base/logging.h" #include "base/scoped_handle.h" #include "skia/ext/platform_canvas.h" -#include "skia/ext/skia_utils_win.h" #include "skia/include/SkShader.h" namespace gfx { @@ -213,8 +213,8 @@ HRESULT NativeTheme::PaintScrollbarTrack(HDC hdc, } else { // Create a 2x2 checkerboard pattern using the 3D face and highlight // colors. - SkColor face = skia::COLORREFToSkColor(color3DFace); - SkColor highlight = skia::COLORREFToSkColor(GetSysColor(COLOR_3DHILIGHT)); + SkColor face = COLORREFToSkColor(color3DFace); + SkColor highlight = COLORREFToSkColor(GetSysColor(COLOR_3DHILIGHT)); SkColor buffer[] = { face, highlight, highlight, face }; SkBitmap bitmap; bitmap.setConfig(SkBitmap::kARGB_8888_Config, 2, 2); @@ -232,7 +232,7 @@ HRESULT NativeTheme::PaintScrollbarTrack(HDC hdc, shader->setLocalMatrix(matrix); SkPaint paint; paint.setShader(shader)->unref(); - canvas->drawIRect(skia::RECTToSkIRect(*target_rect), paint); + canvas->drawIRect(RECTToSkIRect(*target_rect), paint); } if (classic_state & DFCS_PUSHED) InvertRect(hdc, target_rect); @@ -466,7 +466,7 @@ HRESULT NativeTheme::GetThemeColor(ThemeName theme, COLORREF color_ref; if (get_theme_color_(handle, part_id, state_id, prop_id, &color_ref) == S_OK) { - *color = skia::COLORREFToSkColor(color_ref); + *color = gfx::COLORREFToSkColor(color_ref); return S_OK; } } @@ -480,7 +480,7 @@ SkColor NativeTheme::GetThemeColorWithDefault(ThemeName theme, int default_sys_color) const { SkColor color; if (GetThemeColor(theme, part_id, state_id, prop_id, &color) != S_OK) - color = skia::COLORREFToSkColor(GetSysColor(default_sys_color)); + color = gfx::COLORREFToSkColor(GetSysColor(default_sys_color)); return color; } diff --git a/base/gfx/skia_utils.cc b/base/gfx/skia_utils.cc new file mode 100644 index 0000000..7b70056 --- /dev/null +++ b/base/gfx/skia_utils.cc @@ -0,0 +1,75 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/gfx/skia_utils.h" + +#include "base/logging.h" +#include "SkRect.h" +#include "SkGradientShader.h" + +namespace { + +COMPILE_ASSERT(offsetof(RECT, left) == offsetof(SkIRect, fLeft), o1); +COMPILE_ASSERT(offsetof(RECT, top) == offsetof(SkIRect, fTop), o2); +COMPILE_ASSERT(offsetof(RECT, right) == offsetof(SkIRect, fRight), o3); +COMPILE_ASSERT(offsetof(RECT, bottom) == offsetof(SkIRect, fBottom), o4); +COMPILE_ASSERT(sizeof(RECT().left) == sizeof(SkIRect().fLeft), o5); +COMPILE_ASSERT(sizeof(RECT().top) == sizeof(SkIRect().fTop), o6); +COMPILE_ASSERT(sizeof(RECT().right) == sizeof(SkIRect().fRight), o7); +COMPILE_ASSERT(sizeof(RECT().bottom) == sizeof(SkIRect().fBottom), o8); +COMPILE_ASSERT(sizeof(RECT) == sizeof(SkIRect), o9); + +} // namespace + +namespace gfx { + +POINT SkPointToPOINT(const SkPoint& point) { + POINT win_point = { SkScalarRound(point.fX), SkScalarRound(point.fY) }; + return win_point; +} + +SkRect RECTToSkRect(const RECT& rect) { + SkRect sk_rect = { SkIntToScalar(rect.left), SkIntToScalar(rect.top), + SkIntToScalar(rect.right), SkIntToScalar(rect.bottom) }; + return sk_rect; +} + +SkShader* CreateGradientShader(int start_point, + int end_point, + SkColor start_color, + SkColor end_color) { + SkColor grad_colors[2] = { start_color, end_color}; + SkPoint grad_points[2]; + grad_points[0].set(SkIntToScalar(0), SkIntToScalar(start_point)); + grad_points[1].set(SkIntToScalar(0), SkIntToScalar(end_point)); + + return SkGradientShader::CreateLinear( + grad_points, grad_colors, NULL, 2, SkShader::kRepeat_TileMode); +} + + +SkColor COLORREFToSkColor(COLORREF color) { +#ifndef _MSC_VER + return SkColorSetRGB(GetRValue(color), GetGValue(color), GetBValue(color)); +#else + // ARGB = 0xFF000000 | ((0BGR -> RGB0) >> 8) + return 0xFF000000u | (_byteswap_ulong(color) >> 8); +#endif +} + +COLORREF SkColorToCOLORREF(SkColor color) { + // Currently, Alpha is always 255 or the color is 0 so there is no need to + // demultiply the channels. If this DCHECK() is ever hit, the full + // (SkColorGetX(color) * 255 / a) will have to be added in the conversion. + DCHECK((0xFF == SkColorGetA(color)) || (0 == color)); +#ifndef _MSC_VER + return RGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color)); +#else + // 0BGR = ((ARGB -> BGRA) >> 8) + return (_byteswap_ulong(color) >> 8); +#endif +} + +} // namespace gfx + diff --git a/base/gfx/skia_utils.h b/base/gfx/skia_utils.h new file mode 100644 index 0000000..8509072 --- /dev/null +++ b/base/gfx/skia_utils.h @@ -0,0 +1,56 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_GFX_SKIA_UTILS_H__ +#define BASE_GFX_SKIA_UTILS_H__ + +#include "SkColor.h" +#include "SkShader.h" + +struct SkIRect; +struct SkPoint; +struct SkRect; +typedef unsigned long DWORD; +typedef DWORD COLORREF; +typedef struct tagPOINT POINT; +typedef struct tagRECT RECT; + +namespace gfx { + +// Converts a Skia point to a Windows POINT. +POINT SkPointToPOINT(const SkPoint& point); + +// Converts a Windows RECT to a Skia rect. +SkRect RECTToSkRect(const RECT& rect); + +// Converts a Windows RECT to a Skia rect. +// Both use same in-memory format. Verified by COMPILE_ASSERT() in +// skia_utils.cc. +inline const SkIRect& RECTToSkIRect(const RECT& rect) { + return reinterpret_cast(rect); +} + +// Converts a Skia rect to a Windows RECT. +// Both use same in-memory format. Verified by COMPILE_ASSERT() in +// skia_utils.cc. +inline const RECT& SkIRectToRECT(const SkIRect& rect) { + return reinterpret_cast(rect); +} + +// Creates a vertical gradient shader. The caller owns the shader. +SkShader* CreateGradientShader(int start_point, + int end_point, + SkColor start_color, + SkColor end_color); + +// Converts COLORREFs (0BGR) to the ARGB layout Skia expects. +SkColor COLORREFToSkColor(COLORREF color); + +// Converts ARGB to COLORREFs (0BGR). +COLORREF SkColorToCOLORREF(SkColor color); + +} // namespace gfx + +#endif + diff --git a/base/gfx/skia_utils_mac.cc b/base/gfx/skia_utils_mac.cc new file mode 100644 index 0000000..b5962c3 --- /dev/null +++ b/base/gfx/skia_utils_mac.cc @@ -0,0 +1,83 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/gfx/skia_utils_mac.h" + +#include "base/logging.h" +#include "SkMatrix.h" +#include "SkRect.h" + +namespace gfx { + +CGAffineTransform SkMatrixToCGAffineTransform(const SkMatrix& matrix) { + // CGAffineTransforms don't support perspective transforms, so make sure + // we don't get those. + DCHECK(matrix[SkMatrix::kMPersp0] == 0.0f); + DCHECK(matrix[SkMatrix::kMPersp1] == 0.0f); + DCHECK(matrix[SkMatrix::kMPersp2] == 1.0f); + + return CGAffineTransformMake(matrix[SkMatrix::kMScaleX], + matrix[SkMatrix::kMSkewY], + matrix[SkMatrix::kMSkewX], + matrix[SkMatrix::kMScaleY], + matrix[SkMatrix::kMTransX], + matrix[SkMatrix::kMTransY]); +} + +SkIRect CGRectToSkIRect(const CGRect& rect) { + SkIRect sk_rect = { + SkScalarRound(rect.origin.x), + SkScalarRound(rect.origin.y), + SkScalarRound(rect.origin.x + rect.size.width), + SkScalarRound(rect.origin.y + rect.size.height) + }; + return sk_rect; +} + +SkRect CGRectToSkRect(const CGRect& rect) { + SkRect sk_rect = { + rect.origin.x, + rect.origin.y, + rect.origin.x + rect.size.width, + rect.origin.y + rect.size.height, + }; + return sk_rect; +} + +CGRect SkIRectToCGRect(const SkIRect& rect) { + CGRect cg_rect = { + { rect.fLeft, rect.fTop }, + { rect.fRight - rect.fLeft, rect.fBottom - rect.fTop } + }; + return cg_rect; +} + +CGRect SkRectToCGRect(const SkRect& rect) { + CGRect cg_rect = { + { rect.fLeft, rect.fTop }, + { rect.fRight - rect.fLeft, rect.fBottom - rect.fTop } + }; + return cg_rect; +} + +// Converts CGColorRef to the ARGB layout Skia expects. +SkColor CGColorRefToSkColor(CGColorRef color) { + DCHECK(CGColorGetNumberOfComponents(color) == 4); + const CGFloat *components = CGColorGetComponents(color); + return SkColorSetARGB(SkScalarRound(255.0 * components[3]), // alpha + SkScalarRound(255.0 * components[0]), // red + SkScalarRound(255.0 * components[1]), // green + SkScalarRound(255.0 * components[2])); // blue +} + +// Converts ARGB to CGColorRef. +CGColorRef SkColorToCGColorRef(SkColor color) { + return CGColorCreateGenericRGB(SkColorGetR(color) / 255.0, + SkColorGetG(color) / 255.0, + SkColorGetB(color) / 255.0, + SkColorGetA(color) / 255.0); +} + +} // namespace gfx + diff --git a/base/gfx/skia_utils_mac.h b/base/gfx/skia_utils_mac.h new file mode 100644 index 0000000..a99905f --- /dev/null +++ b/base/gfx/skia_utils_mac.h @@ -0,0 +1,51 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + + +#ifndef BASE_GFX_SKIA_UTILS_MAC_H__ +#define BASE_GFX_SKIA_UTILS_MAC_H__ + +#include "SkColor.h" +#include + +struct SkMatrix; +struct SkIRect; +struct SkPoint; +struct SkRect; + +namespace gfx { + +// Converts a Skia point to a CoreGraphics CGPoint. +// Both use same in-memory format. +inline const CGPoint& SkPointToCGPoint(const SkPoint& point) { + return reinterpret_cast(point); +} + +// Converts a CoreGraphics point to a Skia CGPoint. +// Both use same in-memory format. +inline const SkPoint& CGPointToSkPoint(const CGPoint& point) { + return reinterpret_cast(point); +} + +// Matrix converters. +CGAffineTransform SkMatrixToCGAffineTransform(const SkMatrix& matrix); + +// Rectangle converters. +SkRect CGRectToSkRect(const CGRect& rect); +SkIRect CGRectToSkIRect(const CGRect& rect); + +// Converts a Skia rect to a CoreGraphics CGRect. +CGRect SkIRectToCGRect(const SkIRect& rect); +CGRect SkRectToCGRect(const SkRect& rect); + +// Converts CGColorRef to the ARGB layout Skia expects. +SkColor CGColorRefToSkColor(CGColorRef color); + +// Converts ARGB to CGColorRef. +CGColorRef SkColorToCGColorRef(SkColor color); + +} // namespace gfx + +#endif + diff --git a/chrome/browser/autocomplete/autocomplete_edit.cc b/chrome/browser/autocomplete/autocomplete_edit.cc index 4cd2d76..cfef6a6 100644 --- a/chrome/browser/autocomplete/autocomplete_edit.cc +++ b/chrome/browser/autocomplete/autocomplete_edit.cc @@ -8,6 +8,7 @@ #include "base/base_drag_source.h" #include "base/clipboard.h" +#include "base/gfx/skia_utils.h" #include "base/iat_patch.h" #include "base/ref_counted.h" #include "base/scoped_clipboard_writer.h" diff --git a/chrome/browser/download/download_util.cc b/chrome/browser/download/download_util.cc index 5af7c47..262c507 100644 --- a/chrome/browser/download/download_util.cc +++ b/chrome/browser/download/download_util.cc @@ -11,6 +11,7 @@ #include "base/base_drag_source.h" #include "base/file_util.h" #include "base/scoped_clipboard_writer.h" +#include "base/gfx/image_operations.h" #include "base/string_util.h" #include "chrome/app/locales/locale_settings.h" #include "chrome/app/theme/theme_resources.h" @@ -24,7 +25,6 @@ #include "chrome/common/resource_bundle.h" #include "chrome/views/view.h" #include "generated_resources.h" -#include "skia/ext/image_operations.h" #include "SkPath.h" #include "SkShader.h" diff --git a/chrome/browser/fav_icon_helper.cc b/chrome/browser/fav_icon_helper.cc index 2f05357..f77b05c 100644 --- a/chrome/browser/fav_icon_helper.cc +++ b/chrome/browser/fav_icon_helper.cc @@ -4,6 +4,7 @@ #include "chrome/browser/fav_icon_helper.h" +#include "base/gfx/image_operations.h" #include "base/gfx/png_decoder.h" #include "base/gfx/png_encoder.h" #include "chrome/browser/navigation_entry.h" @@ -12,7 +13,6 @@ #include "chrome/browser/render_view_host.h" #include "chrome/browser/web_contents.h" #include "chrome/common/gfx/favicon_size.h" -#include "skia/ext/image_operations.h" FavIconHelper::FavIconHelper(WebContents* web_contents) : web_contents_(web_contents), @@ -257,8 +257,8 @@ SkBitmap FavIconHelper::ConvertToFavIconSize(const SkBitmap& image) { int height = image.height(); if (width > 0 && height > 0) { calc_favicon_target_size(&width, &height); - return skia::ImageOperations::Resize( - image, skia::ImageOperations::RESIZE_LANCZOS3, + return gfx::ImageOperations::Resize( + image, gfx::ImageOperations::RESIZE_LANCZOS3, gfx::Size(width, height)); } return image; diff --git a/chrome/browser/importer/importer.cc b/chrome/browser/importer/importer.cc index a329cfb..3ce8996 100644 --- a/chrome/browser/importer/importer.cc +++ b/chrome/browser/importer/importer.cc @@ -8,6 +8,7 @@ #include #include "base/file_util.h" +#include "base/gfx/image_operations.h" #include "base/gfx/png_encoder.h" #include "base/string_util.h" #include "chrome/browser/bookmarks/bookmark_model.h" @@ -30,7 +31,6 @@ #include "chrome/common/pref_service.h" #include "chrome/common/win_util.h" #include "chrome/views/window.h" -#include "skia/ext/image_operations.h" #include "webkit/glue/image_decoder.h" #include "generated_resources.h" @@ -384,8 +384,8 @@ bool Importer::ReencodeFavicon(const unsigned char* src_data, size_t src_len, int new_width = decoded.width(); int new_height = decoded.height(); calc_favicon_target_size(&new_width, &new_height); - decoded = skia::ImageOperations::Resize( - decoded, skia::ImageOperations::RESIZE_LANCZOS3, + decoded = gfx::ImageOperations::Resize( + decoded, gfx::ImageOperations::RESIZE_LANCZOS3, gfx::Size(new_width, new_height)); } diff --git a/chrome/browser/views/bookmark_bar_view.cc b/chrome/browser/views/bookmark_bar_view.cc index 49d817b..aaca5af 100644 --- a/chrome/browser/views/bookmark_bar_view.cc +++ b/chrome/browser/views/bookmark_bar_view.cc @@ -7,6 +7,7 @@ #include #include "base/base_drag_source.h" +#include "base/gfx/skia_utils.h" #include "chrome/app/theme/theme_resources.h" #include "chrome/browser/bookmarks/bookmark_context_menu.h" #include "chrome/browser/bookmarks/bookmark_utils.h" @@ -44,7 +45,6 @@ #include "chrome/views/widget.h" #include "chrome/views/window.h" #include "generated_resources.h" -#include "skia/ext/skia_utils.h" using views::BaseButton; using views::DropTargetEvent; @@ -255,7 +255,7 @@ class BookmarkButton : public views::TextButton { // the parent's actual bounds because they differ from what is painted. SkPaint paint; paint.setAlpha(static_cast((1.0 - animation_value) * 255)); - paint.setShader(skia::CreateGradientShader(0, + paint.setShader(gfx::CreateGradientShader(0, view->height() + kTopMargin + kBottomMargin, kTopBorderColor, kBackgroundColor))->safeUnref(); @@ -603,16 +603,16 @@ class ButtonSeparatorView : public views::View { virtual void Paint(ChromeCanvas* canvas) { SkPaint paint; - paint.setShader(skia::CreateGradientShader(0, - height() / 2, - kTopBorderColor, - kSeparatorColor))->safeUnref(); + paint.setShader(gfx::CreateGradientShader(0, + height() / 2, + kTopBorderColor, + kSeparatorColor))->safeUnref(); SkRect rc = {SkIntToScalar(kSeparatorStartX), SkIntToScalar(0), SkIntToScalar(1), SkIntToScalar(height() / 2) }; canvas->drawRect(rc, paint); SkPaint paint_down; - paint_down.setShader(skia::CreateGradientShader(height() / 2, + paint_down.setShader(gfx::CreateGradientShader(height() / 2, height(), kSeparatorColor, kBackgroundColor))->safeUnref(); @@ -904,10 +904,10 @@ void BookmarkBarView::Paint(ChromeCanvas* canvas) { // Draw our background. SkPaint paint; paint.setAntiAlias(true); - paint.setShader(skia::CreateGradientShader(0, - height(), - kTopBorderColor, - kBackgroundColor))->safeUnref(); + paint.setShader(gfx::CreateGradientShader(0, + height(), + kTopBorderColor, + kBackgroundColor))->safeUnref(); canvas->drawRoundRect(rect, SkDoubleToScalar(roundness), @@ -924,10 +924,10 @@ void BookmarkBarView::Paint(ChromeCanvas* canvas) { SkDoubleToScalar(roundness), border_paint); } else { SkPaint paint; - paint.setShader(skia::CreateGradientShader(0, - height(), - kTopBorderColor, - kBackgroundColor))->safeUnref(); + paint.setShader(gfx::CreateGradientShader(0, + height(), + kTopBorderColor, + kBackgroundColor))->safeUnref(); canvas->FillRectInt(0, 0, width(), height(), paint); canvas->FillRectInt(kTopBorderColor, 0, 0, width(), 1); diff --git a/chrome/browser/views/bookmark_manager_view.cc b/chrome/browser/views/bookmark_manager_view.cc index 684c252..c0c307e 100644 --- a/chrome/browser/views/bookmark_manager_view.cc +++ b/chrome/browser/views/bookmark_manager_view.cc @@ -6,6 +6,7 @@ #include +#include "base/gfx/skia_utils.h" #include "chrome/app/locales/locale_settings.h" #include "chrome/browser/bookmarks/bookmark_folder_tree_model.h" #include "chrome/browser/bookmarks/bookmark_html_writer.h" @@ -30,8 +31,8 @@ #include "chrome/views/menu_button.h" #include "chrome/views/single_split_view.h" #include "chrome/views/window.h" + #include "generated_resources.h" -#include "skia/ext/skia_utils.h" // If non-null, there is an open editor and this is the window it is contained // in it. @@ -298,7 +299,7 @@ void BookmarkManagerView::PaintBackground(ChromeCanvas* canvas) { canvas->drawColor(kBackgroundColorBottom, SkPorterDuff::kSrc_Mode); SkPaint paint; - paint.setShader(skia::CreateGradientShader(0, kBackgroundGradientHeight, + paint.setShader(gfx::CreateGradientShader(0, kBackgroundGradientHeight, kBackgroundColorTop, kBackgroundColorBottom))->safeUnref(); canvas->FillRectInt(0, 0, width(), kBackgroundGradientHeight, paint); diff --git a/chrome/browser/views/options/content_page_view.cc b/chrome/browser/views/options/content_page_view.cc index a534a4b..e4e443d 100644 --- a/chrome/browser/views/options/content_page_view.cc +++ b/chrome/browser/views/options/content_page_view.cc @@ -11,6 +11,7 @@ #include "base/file_util.h" #include "base/gfx/native_theme.h" +#include "base/gfx/skia_utils.h" #include "chrome/app/theme/theme_resources.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/shell_dialogs.h" @@ -30,7 +31,6 @@ #include "chrome/views/text_field.h" #include "chrome/views/widget.h" #include "generated_resources.h" -#include "skia/ext/skia_utils_win.h" #include "skia/include/SkBitmap.h" namespace { @@ -102,7 +102,7 @@ void FileDisplayArea::Paint(ChromeCanvas* canvas) { RECT rect = { 0, 0, width(), height() }; gfx::NativeTheme::instance()->PaintTextField( dc, EP_EDITTEXT, ETS_READONLY, 0, &rect, - skia::SkColorToCOLORREF(text_field_background_color_), true, true); + gfx::SkColorToCOLORREF(text_field_background_color_), true, true); canvas->endPlatformPaint(); canvas->DrawBitmapInt(default_folder_icon_, icon_bounds_.x(), icon_bounds_.y()); diff --git a/chrome/browser/views/options/fonts_page_view.cc b/chrome/browser/views/options/fonts_page_view.cc index d73191b..b41fb55 100644 --- a/chrome/browser/views/options/fonts_page_view.cc +++ b/chrome/browser/views/options/fonts_page_view.cc @@ -10,6 +10,7 @@ #include "base/file_util.h" #include "base/gfx/native_theme.h" +#include "base/gfx/skia_utils.h" #include "base/string_util.h" #include "chrome/app/theme/theme_resources.h" #include "chrome/app/locales/locale_settings.h" diff --git a/chrome/browser/views/options/languages_page_view.cc b/chrome/browser/views/options/languages_page_view.cc index e9a1e8b..118ac10 100644 --- a/chrome/browser/views/options/languages_page_view.cc +++ b/chrome/browser/views/options/languages_page_view.cc @@ -11,6 +11,7 @@ #include "base/file_util.h" #include "base/string_util.h" #include "base/gfx/native_theme.h" +#include "base/gfx/skia_utils.h" #include "base/string_util.h" #include "chrome/app/theme/theme_resources.h" #include "chrome/browser/browser_process.h" diff --git a/chrome/browser/views/options/options_group_view.cc b/chrome/browser/views/options/options_group_view.cc index 9ff07f5..bdf76ea 100644 --- a/chrome/browser/views/options/options_group_view.cc +++ b/chrome/browser/views/options/options_group_view.cc @@ -8,6 +8,7 @@ #include "chrome/browser/views/options/options_group_view.h" #include "base/gfx/native_theme.h" +#include "base/gfx/skia_utils.h" #include "chrome/app/locales/locale_settings.h" #include "chrome/browser/views/standard_layout.h" #include "chrome/common/gfx/chrome_font.h" diff --git a/chrome/browser/views/sad_tab_view.cc b/chrome/browser/views/sad_tab_view.cc index e22aea2..7b34bcb 100644 --- a/chrome/browser/views/sad_tab_view.cc +++ b/chrome/browser/views/sad_tab_view.cc @@ -10,7 +10,6 @@ #include "chrome/common/l10n_util.h" #include "chrome/common/resource_bundle.h" #include "generated_resources.h" -#include "skia/ext/skia_utils.h" #include "skia/include/SkGradientShader.h" static const int kSadTabOffset = -64; @@ -35,9 +34,17 @@ SadTabView::SadTabView() { InitClass(); } +static SkShader* CreateGradientShader(int end_point) { + SkColor grad_colors[2] = { kBackgroundColor, kBackgroundEndColor }; + SkPoint grad_points[2]; + grad_points[0].set(SkIntToScalar(0), SkIntToScalar(0)); + grad_points[1].set(SkIntToScalar(0), SkIntToScalar(end_point)); + return SkGradientShader::CreateLinear( + grad_points, grad_colors, NULL, 2, SkShader::kRepeat_TileMode); +} + void SadTabView::Paint(ChromeCanvas* canvas) { - SkShader* background_shader = skia::CreateGradientShader( - 0, height(), kBackgroundColor, kBackgroundEndColor); + SkShader* background_shader = CreateGradientShader(height()); SkPaint paint; paint.setShader(background_shader); background_shader->unref(); diff --git a/chrome/browser/views/tabs/tab_renderer.cc b/chrome/browser/views/tabs/tab_renderer.cc index 4581f6d..f1d00b3 100644 --- a/chrome/browser/views/tabs/tab_renderer.cc +++ b/chrome/browser/views/tabs/tab_renderer.cc @@ -6,6 +6,7 @@ #include "chrome/browser/views/tabs/tab_renderer.h" +#include "base/gfx/image_operations.h" #include "chrome/app/theme/theme_resources.h" #include "chrome/browser/browser.h" #include "chrome/browser/tabs/tab_strip_model.h" @@ -16,7 +17,6 @@ #include "chrome/common/resource_bundle.h" #include "chrome/common/win_util.h" #include "generated_resources.h" -#include "skia/ext/image_operations.h" static const int kLeftPadding = 16; static const int kTopPadding = 6; @@ -586,13 +586,13 @@ void TabRenderer::PaintActiveTabBackground(ChromeCanvas* canvas) { void TabRenderer::PaintHoverTabBackground(ChromeCanvas* canvas, double opacity) { bool is_otr = data_.off_the_record; - SkBitmap left = skia::ImageOperations::CreateBlendedBitmap( + SkBitmap left = gfx::ImageOperations::CreateBlendedBitmap( (is_otr ? *tab_inactive_otr_l : *tab_inactive_l), *tab_hover_l, opacity); - SkBitmap center = skia::ImageOperations::CreateBlendedBitmap( + SkBitmap center = gfx::ImageOperations::CreateBlendedBitmap( (is_otr ? *tab_inactive_otr_c : *tab_inactive_c), *tab_hover_c, opacity); - SkBitmap right = skia::ImageOperations::CreateBlendedBitmap( + SkBitmap right = gfx::ImageOperations::CreateBlendedBitmap( (is_otr ? *tab_inactive_otr_r : *tab_inactive_r), *tab_hover_r, opacity); diff --git a/chrome/common/gfx/color_utils.cc b/chrome/common/gfx/color_utils.cc index cdb4c0c..0b40436 100644 --- a/chrome/common/gfx/color_utils.cc +++ b/chrome/common/gfx/color_utils.cc @@ -12,13 +12,10 @@ #include "chrome/common/gfx/color_utils.h" #include "base/basictypes.h" +#include "base/gfx/skia_utils.h" #include "base/logging.h" #include "skia/include/SkBitmap.h" -#if defined(OS_WIN) -#include "skia/ext/skia_utils_win.h" -#endif - namespace color_utils { // These transformations are based on the equations in: @@ -255,7 +252,7 @@ SkColor SetColorAlpha(SkColor c, SkAlpha alpha) { SkColor GetSysSkColor(int which) { #if defined(OS_WIN) - return skia::COLORREFToSkColor(::GetSysColor(which)); + return gfx::COLORREFToSkColor(::GetSysColor(which)); #else NOTIMPLEMENTED(); return SK_ColorLTGRAY; diff --git a/chrome/common/gfx/icon_util.cc b/chrome/common/gfx/icon_util.cc index ae5e174..e717c79 100644 --- a/chrome/common/gfx/icon_util.cc +++ b/chrome/common/gfx/icon_util.cc @@ -3,12 +3,11 @@ // found in the LICENSE file. #include "chrome/common/gfx/icon_util.h" - #include "base/file_util.h" +#include "base/gfx/image_operations.h" #include "base/gfx/size.h" #include "base/logging.h" #include "chrome/common/win_util.h" -#include "skia/ext/image_operations.h" #include "skia/include/SkBitmap.h" // Defining the dimensions for the icon images. We store only one value because @@ -404,8 +403,8 @@ void IconUtil::CreateResizedBitmapSet(const SkBitmap& bitmap_to_resize, inserted_original_bitmap = true; } } - bitmaps->push_back(skia::ImageOperations::Resize( - bitmap_to_resize, skia::ImageOperations::RESIZE_LANCZOS3, + bitmaps->push_back(gfx::ImageOperations::Resize( + bitmap_to_resize, gfx::ImageOperations::RESIZE_LANCZOS3, gfx::Size(icon_dimensions_[i], icon_dimensions_[i]))); } diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index e28a6c7..23fab18 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -10,6 +10,7 @@ #include "base/command_line.h" #include "base/gfx/gdi_util.h" +#include "base/gfx/image_operations.h" #include "base/gfx/native_theme.h" #include "base/gfx/png_encoder.h" #include "base/string_piece.h" @@ -37,7 +38,6 @@ #include "net/base/escape.h" #include "net/base/net_errors.h" #include "skia/ext/bitmap_platform_device.h" -#include "skia/ext/image_operations.h" #include "skia/ext/vector_canvas.h" #include "webkit/default_plugin/default_plugin_shared.h" #include "webkit/glue/dom_operations.h" @@ -57,6 +57,7 @@ #include "webkit/glue/weburlrequest.h" #include "webkit/glue/webview.h" #include "webkit/glue/plugins/webplugin_delegate_impl.h" +//#include "webkit/port/platform/graphics/PlatformContextSkia.h" #include "generated_resources.h" @@ -797,8 +798,8 @@ bool RenderView::CaptureThumbnail(WebFrame* frame, device->accessBitmap(false).extractSubset(&subset, src_rect); // Resample the subset that we want to get it the right size. - *thumbnail = skia::ImageOperations::Resize( - subset, skia::ImageOperations::RESIZE_LANCZOS3, gfx::Size(w, h)); + *thumbnail = gfx::ImageOperations::Resize( + subset, gfx::ImageOperations::RESIZE_LANCZOS3, gfx::Size(w, h)); score->boring_score = CalculateBoringScore(thumbnail); diff --git a/chrome/views/background.cc b/chrome/views/background.cc index 1aa631e..72352b7 100644 --- a/chrome/views/background.cc +++ b/chrome/views/background.cc @@ -4,11 +4,11 @@ #include "chrome/views/background.h" +#include "base/gfx/skia_utils.h" #include "base/logging.h" #include "chrome/common/gfx/chrome_canvas.h" #include "chrome/views/painter.h" #include "chrome/views/view.h" -#include "skia/ext/skia_utils_win.h" #include "skia/include/SkPaint.h" namespace views { @@ -68,7 +68,7 @@ Background::~Background() { void Background::SetNativeControlColor(SkColor color) { DeleteObject(native_control_brush_); - native_control_brush_ = CreateSolidBrush(skia::SkColorToCOLORREF(color)); + native_control_brush_ = CreateSolidBrush(gfx::SkColorToCOLORREF(color)); } //static diff --git a/chrome/views/button.cc b/chrome/views/button.cc index 36c228a..93e2e3c 100644 --- a/chrome/views/button.cc +++ b/chrome/views/button.cc @@ -7,12 +7,12 @@ #include #include +#include "base/gfx/image_operations.h" #include "chrome/app/chrome_dll_resource.h" #include "chrome/common/gfx/chrome_canvas.h" #include "chrome/common/l10n_util.h" #include "chrome/common/throb_animation.h" #include "chrome/views/event.h" -#include "skia/ext/image_operations.h" #include "generated_resources.h" @@ -105,7 +105,7 @@ SkBitmap Button::GetImageToPaint() { SkBitmap img; if (!images_[BS_HOT].isNull() && hover_animation_->IsAnimating()) { - img = skia::ImageOperations::CreateBlendedBitmap(images_[BS_NORMAL], + img = gfx::ImageOperations::CreateBlendedBitmap(images_[BS_NORMAL], images_[BS_HOT], hover_animation_->GetCurrentValue()); } else { img = images_[GetState()]; diff --git a/chrome/views/chrome_menu.cc b/chrome/views/chrome_menu.cc index 4d12f3b..549bedf 100644 --- a/chrome/views/chrome_menu.cc +++ b/chrome/views/chrome_menu.cc @@ -10,6 +10,7 @@ #include "base/base_drag_source.h" #include "base/gfx/native_theme.h" +#include "base/gfx/skia_utils.h" #include "base/message_loop.h" #include "base/task.h" #include "base/timer.h" diff --git a/chrome/views/single_split_view.cc b/chrome/views/single_split_view.cc index a7832b6..2550c57 100644 --- a/chrome/views/single_split_view.cc +++ b/chrome/views/single_split_view.cc @@ -4,9 +4,9 @@ #include "chrome/views/single_split_view.h" +#include "base/gfx/skia_utils.h" #include "chrome/common/gfx/chrome_canvas.h" #include "chrome/views/background.h" -#include "skia/ext/skia_utils_win.h" namespace views { @@ -19,7 +19,7 @@ SingleSplitView::SingleSplitView(View* leading, View* trailing) AddChildView(trailing); set_background( views::Background::CreateSolidBackground( - skia::COLORREFToSkColor(GetSysColor(COLOR_3DFACE)))); + gfx::COLORREFToSkColor(GetSysColor(COLOR_3DFACE)))); } void SingleSplitView::Layout() { diff --git a/chrome/views/tabbed_pane.cc b/chrome/views/tabbed_pane.cc index 4a63b47..2638972 100644 --- a/chrome/views/tabbed_pane.cc +++ b/chrome/views/tabbed_pane.cc @@ -7,6 +7,7 @@ #include #include "base/gfx/native_theme.h" +#include "base/gfx/skia_utils.h" #include "base/logging.h" #include "chrome/common/gfx/chrome_canvas.h" #include "chrome/common/gfx/chrome_font.h" diff --git a/chrome/views/table_view.cc b/chrome/views/table_view.cc index 73f456f1..8298cf6 100644 --- a/chrome/views/table_view.cc +++ b/chrome/views/table_view.cc @@ -9,6 +9,7 @@ #include "base/string_util.h" #include "base/win_util.h" +#include "base/gfx/skia_utils.h" #include "chrome/common/gfx/chrome_canvas.h" #include "chrome/common/gfx/favicon_size.h" #include "chrome/common/gfx/icon_util.h" @@ -17,7 +18,6 @@ #include "chrome/views/hwnd_view.h" #include "SkBitmap.h" #include "SkColorFilter.h" -#include "skia/ext/skia_utils_win.h" namespace views { @@ -1203,10 +1203,10 @@ LRESULT TableView::OnCustomDraw(NMLVCUSTOMDRAW* draw_info) { custom_cell_font_ = CreateFontIndirect(&logfont); SelectObject(draw_info->nmcd.hdc, custom_cell_font_); draw_info->clrText = foreground.color_is_set - ? skia::SkColorToCOLORREF(foreground.color) + ? gfx::SkColorToCOLORREF(foreground.color) : CLR_DEFAULT; draw_info->clrTextBk = background.color_is_set - ? skia::SkColorToCOLORREF(background.color) + ? gfx::SkColorToCOLORREF(background.color) : CLR_DEFAULT; return CDRF_NEWFONT; } @@ -1256,7 +1256,7 @@ LRESULT TableView::OnCustomDraw(NMLVCUSTOMDRAW* draw_info) { // background (or rather windows paints background, then invokes // this twice). As such, we always fill in the background. canvas.drawColor( - skia::COLORREFToSkColor(GetSysColor(bg_color_index)), + gfx::COLORREFToSkColor(GetSysColor(bg_color_index)), SkPorterDuff::kSrc_Mode); // + 1 for padding (we declared the image as 18x18 in the list- // view when they are 16x16 so we get an extra pixel of padding). diff --git a/chrome/views/text_field.cc b/chrome/views/text_field.cc index 92797a4..24fdc5a 100644 --- a/chrome/views/text_field.cc +++ b/chrome/views/text_field.cc @@ -12,6 +12,7 @@ #include #include "base/gfx/native_theme.h" +#include "base/gfx/skia_utils.h" #include "base/scoped_clipboard_writer.h" #include "base/string_util.h" #include "base/win_util.h" @@ -24,8 +25,8 @@ #include "chrome/views/hwnd_view.h" #include "chrome/views/menu.h" #include "chrome/views/widget.h" + #include "generated_resources.h" -#include "skia/ext/skia_utils_win.h" using gfx::NativeTheme; @@ -1086,7 +1087,7 @@ void TextField::UpdateEditBackgroundColor() { COLORREF bg_color; if (!use_default_background_color_) - bg_color = skia::SkColorToCOLORREF(background_color_); + bg_color = gfx::SkColorToCOLORREF(background_color_); else bg_color = GetSysColor(read_only_ ? COLOR_3DFACE : COLOR_WINDOW); edit_->SetBackgroundColor(bg_color); diff --git a/skia/SConscript b/skia/SConscript index fbafc92..00b8e1b 100644 --- a/skia/SConscript +++ b/skia/SConscript @@ -152,10 +152,6 @@ input_files = [ 'sgl/SkUtils.cpp', 'sgl/SkWriter32.cpp', 'sgl/SkXfermode.cpp', - - 'ext/convolver.cc', - 'ext/image_operations.cc', - 'ext/skia_utils.cc', ] if env['PLATFORM'] == 'posix': @@ -180,13 +176,11 @@ if env['PLATFORM'] == 'darwin': input_files.append('ext/bitmap_platform_device_mac.cc') input_files.append('ext/platform_canvas_mac.cc') input_files.append('ext/platform_device_mac.cc') - input_files.append('ext/skia_utils_mac.cc') if env['PLATFORM'] == 'win32': input_files.append('ext/bitmap_platform_device_win.cc') input_files.append('ext/platform_canvas_win.cc') input_files.append('ext/platform_device_win.cc') - input_files.append('ext/skia_utils_win.cc') input_files.append('ext/vector_canvas.cc') input_files.append('ext/vector_device.cc') diff --git a/skia/ext/bitmap_platform_device_mac.cc b/skia/ext/bitmap_platform_device_mac.cc index 52ce586..d4458d7 100755 --- a/skia/ext/bitmap_platform_device_mac.cc +++ b/skia/ext/bitmap_platform_device_mac.cc @@ -10,8 +10,8 @@ #include "SkRegion.h" #include "SkUtils.h" +#include "base/gfx/skia_utils_mac.h" #include "base/logging.h" -#include "skia/ext/skia_utils_mac.h" namespace gfx { diff --git a/skia/ext/convolver.cc b/skia/ext/convolver.cc deleted file mode 100644 index c854019..0000000 --- a/skia/ext/convolver.cc +++ /dev/null @@ -1,336 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "skia/ext/convolver.h" - -#include "base/basictypes.h" -#include "base/logging.h" - -namespace skia { - -namespace { - -// Converts the argument to an 8-bit unsigned value by clamping to the range -// 0-255. -inline uint8 ClampTo8(int32 a) { - if (static_cast(a) < 256) - return a; // Avoid the extra check in the common case. - if (a < 0) - return 0; - return 255; -} - -// Stores a list of rows in a circular buffer. The usage is you write into it -// by calling AdvanceRow. It will keep track of which row in the buffer it -// should use next, and the total number of rows added. -class CircularRowBuffer { - public: - // The number of pixels in each row is given in |source_row_pixel_width|. - // The maximum number of rows needed in the buffer is |max_y_filter_size| - // (we only need to store enough rows for the biggest filter). - // - // We use the |first_input_row| to compute the coordinates of all of the - // following rows returned by Advance(). - CircularRowBuffer(int dest_row_pixel_width, int max_y_filter_size, - int first_input_row) - : row_byte_width_(dest_row_pixel_width * 4), - num_rows_(max_y_filter_size), - next_row_(0), - next_row_coordinate_(first_input_row) { - buffer_.resize(row_byte_width_ * max_y_filter_size); - row_addresses_.resize(num_rows_); - } - - // Moves to the next row in the buffer, returning a pointer to the beginning - // of it. - uint8* AdvanceRow() { - uint8* row = &buffer_[next_row_ * row_byte_width_]; - next_row_coordinate_++; - - // Set the pointer to the next row to use, wrapping around if necessary. - next_row_++; - if (next_row_ == num_rows_) - next_row_ = 0; - return row; - } - - // Returns a pointer to an "unrolled" array of rows. These rows will start - // at the y coordinate placed into |*first_row_index| and will continue in - // order for the maximum number of rows in this circular buffer. - // - // The |first_row_index_| may be negative. This means the circular buffer - // starts before the top of the image (it hasn't been filled yet). - uint8* const* GetRowAddresses(int* first_row_index) { - // Example for a 4-element circular buffer holding coords 6-9. - // Row 0 Coord 8 - // Row 1 Coord 9 - // Row 2 Coord 6 <- next_row_ = 2, next_row_coordinate_ = 10. - // Row 3 Coord 7 - // - // The "next" row is also the first (lowest) coordinate. This computation - // may yield a negative value, but that's OK, the math will work out - // since the user of this buffer will compute the offset relative - // to the first_row_index and the negative rows will never be used. - *first_row_index = next_row_coordinate_ - num_rows_; - - int cur_row = next_row_; - for (int i = 0; i < num_rows_; i++) { - row_addresses_[i] = &buffer_[cur_row * row_byte_width_]; - - // Advance to the next row, wrapping if necessary. - cur_row++; - if (cur_row == num_rows_) - cur_row = 0; - } - return &row_addresses_[0]; - } - - private: - // The buffer storing the rows. They are packed, each one row_byte_width_. - std::vector buffer_; - - // Number of bytes per row in the |buffer_|. - int row_byte_width_; - - // The number of rows available in the buffer. - int num_rows_; - - // The next row index we should write into. This wraps around as the - // circular buffer is used. - int next_row_; - - // The y coordinate of the |next_row_|. This is incremented each time a - // new row is appended and does not wrap. - int next_row_coordinate_; - - // Buffer used by GetRowAddresses(). - std::vector row_addresses_; -}; - -// Convolves horizontally along a single row. The row data is given in -// |src_data| and continues for the num_values() of the filter. -template -void ConvolveHorizontally(const uint8* src_data, - const ConvolusionFilter1D& filter, - unsigned char* out_row) { - // Loop over each pixel on this row in the output image. - int num_values = filter.num_values(); - for (int out_x = 0; out_x < num_values; out_x++) { - // Get the filter that determines the current output pixel. - int filter_offset, filter_length; - const int16* filter_values = - filter.FilterForValue(out_x, &filter_offset, &filter_length); - - // Compute the first pixel in this row that the filter affects. It will - // touch |filter_length| pixels (4 bytes each) after this. - const uint8* row_to_filter = &src_data[filter_offset * 4]; - - // Apply the filter to the row to get the destination pixel in |accum|. - int32 accum[4] = {0}; - for (int filter_x = 0; filter_x < filter_length; filter_x++) { - int16 cur_filter = filter_values[filter_x]; - accum[0] += cur_filter * row_to_filter[filter_x * 4 + 0]; - accum[1] += cur_filter * row_to_filter[filter_x * 4 + 1]; - accum[2] += cur_filter * row_to_filter[filter_x * 4 + 2]; - if (has_alpha) - accum[3] += cur_filter * row_to_filter[filter_x * 4 + 3]; - } - - // Bring this value back in range. All of the filter scaling factors - // are in fixed point with kShiftBits bits of fractional part. - accum[0] >>= ConvolusionFilter1D::kShiftBits; - accum[1] >>= ConvolusionFilter1D::kShiftBits; - accum[2] >>= ConvolusionFilter1D::kShiftBits; - if (has_alpha) - accum[3] >>= ConvolusionFilter1D::kShiftBits; - - // Store the new pixel. - out_row[out_x * 4 + 0] = ClampTo8(accum[0]); - out_row[out_x * 4 + 1] = ClampTo8(accum[1]); - out_row[out_x * 4 + 2] = ClampTo8(accum[2]); - if (has_alpha) - out_row[out_x * 4 + 3] = ClampTo8(accum[3]); - } -} - -// Does vertical convolusion to produce one output row. The filter values and -// length are given in the first two parameters. These are applied to each -// of the rows pointed to in the |source_data_rows| array, with each row -// being |pixel_width| wide. -// -// The output must have room for |pixel_width * 4| bytes. -template -void ConvolveVertically(const int16* filter_values, - int filter_length, - uint8* const* source_data_rows, - int pixel_width, - uint8* out_row) { - // We go through each column in the output and do a vertical convolusion, - // generating one output pixel each time. - for (int out_x = 0; out_x < pixel_width; out_x++) { - // Compute the number of bytes over in each row that the current column - // we're convolving starts at. The pixel will cover the next 4 bytes. - int byte_offset = out_x * 4; - - // Apply the filter to one column of pixels. - int32 accum[4] = {0}; - for (int filter_y = 0; filter_y < filter_length; filter_y++) { - int16 cur_filter = filter_values[filter_y]; - accum[0] += cur_filter * source_data_rows[filter_y][byte_offset + 0]; - accum[1] += cur_filter * source_data_rows[filter_y][byte_offset + 1]; - accum[2] += cur_filter * source_data_rows[filter_y][byte_offset + 2]; - if (has_alpha) - accum[3] += cur_filter * source_data_rows[filter_y][byte_offset + 3]; - } - - // Bring this value back in range. All of the filter scaling factors - // are in fixed point with kShiftBits bits of precision. - accum[0] >>= ConvolusionFilter1D::kShiftBits; - accum[1] >>= ConvolusionFilter1D::kShiftBits; - accum[2] >>= ConvolusionFilter1D::kShiftBits; - if (has_alpha) - accum[3] >>= ConvolusionFilter1D::kShiftBits; - - // Store the new pixel. - out_row[byte_offset + 0] = ClampTo8(accum[0]); - out_row[byte_offset + 1] = ClampTo8(accum[1]); - out_row[byte_offset + 2] = ClampTo8(accum[2]); - if (has_alpha) { - uint8 alpha = ClampTo8(accum[3]); - - // Make sure the alpha channel doesn't come out larger than any of the - // color channels. We use premultipled alpha channels, so this should - // never happen, but rounding errors will cause this from time to time. - // These "impossible" colors will cause overflows (and hence random pixel - // values) when the resulting bitmap is drawn to the screen. - // - // We only need to do this when generating the final output row (here). - int max_color_channel = std::max(out_row[byte_offset + 0], - std::max(out_row[byte_offset + 1], out_row[byte_offset + 2])); - if (alpha < max_color_channel) - out_row[byte_offset + 3] = max_color_channel; - else - out_row[byte_offset + 3] = alpha; - } else { - // No alpha channel, the image is opaque. - out_row[byte_offset + 3] = 0xff; - } - } -} - -} // namespace - -// ConvolusionFilter1D --------------------------------------------------------- - -void ConvolusionFilter1D::AddFilter(int filter_offset, - const float* filter_values, - int filter_length) { - FilterInstance instance; - instance.data_location = static_cast(filter_values_.size()); - instance.offset = filter_offset; - instance.length = filter_length; - filters_.push_back(instance); - - DCHECK(filter_length > 0); - for (int i = 0; i < filter_length; i++) - filter_values_.push_back(FloatToFixed(filter_values[i])); - - max_filter_ = std::max(max_filter_, filter_length); -} - -void ConvolusionFilter1D::AddFilter(int filter_offset, - const int16* filter_values, - int filter_length) { - FilterInstance instance; - instance.data_location = static_cast(filter_values_.size()); - instance.offset = filter_offset; - instance.length = filter_length; - filters_.push_back(instance); - - DCHECK(filter_length > 0); - for (int i = 0; i < filter_length; i++) - filter_values_.push_back(filter_values[i]); - - max_filter_ = std::max(max_filter_, filter_length); -} - -// BGRAConvolve2D ------------------------------------------------------------- - -void BGRAConvolve2D(const uint8* source_data, - int source_byte_row_stride, - bool source_has_alpha, - const ConvolusionFilter1D& filter_x, - const ConvolusionFilter1D& filter_y, - uint8* output) { - int max_y_filter_size = filter_y.max_filter(); - - // The next row in the input that we will generate a horizontally - // convolved row for. If the filter doesn't start at the beginning of the - // image (this is the case when we are only resizing a subset), then we - // don't want to generate any output rows before that. Compute the starting - // row for convolusion as the first pixel for the first vertical filter. - int filter_offset, filter_length; - const int16* filter_values = - filter_y.FilterForValue(0, &filter_offset, &filter_length); - int next_x_row = filter_offset; - - // We loop over each row in the input doing a horizontal convolusion. This - // will result in a horizontally convolved image. We write the results into - // a circular buffer of convolved rows and do vertical convolusion as rows - // are available. This prevents us from having to store the entire - // intermediate image and helps cache coherency. - CircularRowBuffer row_buffer(filter_x.num_values(), max_y_filter_size, - filter_offset); - - // Loop over every possible output row, processing just enough horizontal - // convolusions to run each subsequent vertical convolusion. - int output_row_byte_width = filter_x.num_values() * 4; - int num_output_rows = filter_y.num_values(); - for (int out_y = 0; out_y < num_output_rows; out_y++) { - filter_values = filter_y.FilterForValue(out_y, - &filter_offset, &filter_length); - - // Generate output rows until we have enough to run the current filter. - while (next_x_row < filter_offset + filter_length) { - if (source_has_alpha) { - ConvolveHorizontally( - &source_data[next_x_row * source_byte_row_stride], - filter_x, row_buffer.AdvanceRow()); - } else { - ConvolveHorizontally( - &source_data[next_x_row * source_byte_row_stride], - filter_x, row_buffer.AdvanceRow()); - } - next_x_row++; - } - - // Compute where in the output image this row of final data will go. - uint8* cur_output_row = &output[out_y * output_row_byte_width]; - - // Get the list of rows that the circular buffer has, in order. - int first_row_in_circular_buffer; - uint8* const* rows_to_convolve = - row_buffer.GetRowAddresses(&first_row_in_circular_buffer); - - // Now compute the start of the subset of those rows that the filter - // needs. - uint8* const* first_row_for_filter = - &rows_to_convolve[filter_offset - first_row_in_circular_buffer]; - - if (source_has_alpha) { - ConvolveVertically(filter_values, filter_length, - first_row_for_filter, - filter_x.num_values(), cur_output_row); - } else { - ConvolveVertically(filter_values, filter_length, - first_row_for_filter, - filter_x.num_values(), cur_output_row); - } - } -} - -} // namespace skia - diff --git a/skia/ext/convolver.h b/skia/ext/convolver.h deleted file mode 100644 index 62c1e30..0000000 --- a/skia/ext/convolver.h +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SKIA_EXT_CONVOLVER_H_ -#define SKIA_EXT_CONVOLVER_H_ - -#include - -#include "base/basictypes.h" - -// avoid confusion with Mac OS X's math library (Carbon) -#if defined(OS_MACOSX) -#undef FloatToFixed -#endif - -namespace skia { - -// Represents a filter in one dimension. Each output pixel has one entry in this -// object for the filter values contributing to it. You build up the filter -// list by calling AddFilter for each output pixel (in order). -// -// We do 2-dimensional convolusion by first convolving each row by one -// ConvolusionFilter1D, then convolving each column by another one. -// -// Entries are stored in fixed point, shifted left by kShiftBits. -class ConvolusionFilter1D { - public: - // The number of bits that fixed point values are shifted by. - enum { kShiftBits = 14 }; - - ConvolusionFilter1D() : max_filter_(0) { - } - - // Convert between floating point and our fixed point representation. - static inline int16 FloatToFixed(float f) { - return static_cast(f * (1 << kShiftBits)); - } - static inline unsigned char FixedToChar(int16 x) { - return static_cast(x >> kShiftBits); - } - - // Returns the maximum pixel span of a filter. - int max_filter() const { return max_filter_; } - - // Returns the number of filters in this filter. This is the dimension of the - // output image. - int num_values() const { return static_cast(filters_.size()); } - - // Appends the given list of scaling values for generating a given output - // pixel. |filter_offset| is the distance from the edge of the image to where - // the scaling factors start. The scaling factors apply to the source pixels - // starting from this position, and going for the next |filter_length| pixels. - // - // You will probably want to make sure your input is normalized (that is, - // all entries in |filter_values| sub to one) to prevent affecting the overall - // brighness of the image. - // - // The filter_length must be > 0. - // - // This version will automatically convert your input to fixed point. - void AddFilter(int filter_offset, - const float* filter_values, - int filter_length); - - // Same as the above version, but the input is already fixed point. - void AddFilter(int filter_offset, - const int16* filter_values, - int filter_length); - - // Retrieves a filter for the given |value_offset|, a position in the output - // image in the direction we're convolving. The offset and length of the - // filter values are put into the corresponding out arguments (see AddFilter - // above for what these mean), and a pointer to the first scaling factor is - // returned. There will be |filter_length| values in this array. - inline const int16* FilterForValue(int value_offset, - int* filter_offset, - int* filter_length) const { - const FilterInstance& filter = filters_[value_offset]; - *filter_offset = filter.offset; - *filter_length = filter.length; - return &filter_values_[filter.data_location]; - } - - private: - struct FilterInstance { - // Offset within filter_values for this instance of the filter. - int data_location; - - // Distance from the left of the filter to the center. IN PIXELS - int offset; - - // Number of values in this filter instance. - int length; - }; - - // Stores the information for each filter added to this class. - std::vector filters_; - - // We store all the filter values in this flat list, indexed by - // |FilterInstance.data_location| to avoid the mallocs required for storing - // each one separately. - std::vector filter_values_; - - // The maximum size of any filter we've added. - int max_filter_; -}; - -// Does a two-dimensional convolusion on the given source image. -// -// It is assumed the source pixel offsets referenced in the input filters -// reference only valid pixels, so the source image size is not required. Each -// row of the source image starts |source_byte_row_stride| after the previous -// one (this allows you to have rows with some padding at the end). -// -// The result will be put into the given output buffer. The destination image -// size will be xfilter.num_values() * yfilter.num_values() pixels. It will be -// in rows of exactly xfilter.num_values() * 4 bytes. -// -// |source_has_alpha| is a hint that allows us to avoid doing computations on -// the alpha channel if the image is opaque. If you don't know, set this to -// true and it will work properly, but setting this to false will be a few -// percent faster if you know the image is opaque. -// -// The layout in memory is assumed to be 4-bytes per pixel in B-G-R-A order -// (this is ARGB when loaded into 32-bit words on a little-endian machine). -void BGRAConvolve2D(const uint8* source_data, - int source_byte_row_stride, - bool source_has_alpha, - const ConvolusionFilter1D& xfilter, - const ConvolusionFilter1D& yfilter, - uint8* output); - -} // namespace skia - -#endif // SKIA_EXT_CONVOLVER_H_ - diff --git a/skia/ext/convolver_unittest.cc b/skia/ext/convolver_unittest.cc deleted file mode 100644 index c0ae734..0000000 --- a/skia/ext/convolver_unittest.cc +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include -#include -#include - -#include "skia/ext/convolver.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace skia { - -namespace { - -// Fills the given filter with impulse functions for the range 0->num_entries. - void FillImpulseFilter(int num_entries, ConvolusionFilter1D* filter) { - float one = 1.0f; - for (int i = 0; i < num_entries; i++) - filter->AddFilter(i, &one, 1); -} - -// Filters the given input with the impulse function, and verifies that it -// does not change. -void TestImpulseConvolusion(const unsigned char* data, int width, int height) { - int byte_count = width * height * 4; - - ConvolusionFilter1D filter_x; - FillImpulseFilter(width, &filter_x); - - ConvolusionFilter1D filter_y; - FillImpulseFilter(height, &filter_y); - - std::vector output; - output.resize(byte_count); - BGRAConvolve2D(data, width * 4, true, filter_x, filter_y, &output[0]); - - // Output should exactly match input. - EXPECT_EQ(0, memcmp(data, &output[0], byte_count)); -} - -// Fills the destination filter with a box filter averaging every two pixels -// to produce the output. -void FillBoxFilter(int size, ConvolusionFilter1D* filter) { - const float box[2] = { 0.5, 0.5 }; - for (int i = 0; i < size; i++) - filter->AddFilter(i * 2, box, 2); -} - -} // namespace - -// Tests that each pixel, when set and run through the impulse filter, does -// not change. -TEST(Convolver, Impulse) { - // We pick an "odd" size that is not likely to fit on any boundaries so that - // we can see if all the widths and paddings are handled properly. - int width = 15; - int height = 31; - int byte_count = width * height * 4; - std::vector input; - input.resize(byte_count); - - unsigned char* input_ptr = &input[0]; - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - for (int channel = 0; channel < 3; channel++) { - memset(input_ptr, 0, byte_count); - input_ptr[(y * width + x) * 4 + channel] = 0xff; - // Always set the alpha channel or it will attempt to "fix" it for us. - input_ptr[(y * width + x) * 4 + 3] = 0xff; - TestImpulseConvolusion(input_ptr, width, height); - } - } - } -} - -// Tests that using a box filter to halve an image results in every square of 4 -// pixels in the original get averaged to a pixel in the output. -TEST(Convolver, Halve) { - static const int kSize = 16; - - int src_width = kSize; - int src_height = kSize; - int src_row_stride = src_width * 4; - int src_byte_count = src_row_stride * src_height; - std::vector input; - input.resize(src_byte_count); - - int dest_width = src_width / 2; - int dest_height = src_height / 2; - int dest_byte_count = dest_width * dest_height * 4; - std::vector output; - output.resize(dest_byte_count); - - // First fill the array with a bunch of random data. - srand(static_cast(time(NULL))); - for (int i = 0; i < src_byte_count; i++) - input[i] = rand() * 255 / RAND_MAX; - - // Compute the filters. - ConvolusionFilter1D filter_x, filter_y; - FillBoxFilter(dest_width, &filter_x); - FillBoxFilter(dest_height, &filter_y); - - // Do the convolusion. - BGRAConvolve2D(&input[0], src_width, true, filter_x, filter_y, &output[0]); - - // Compute the expected results and check, allowing for a small difference - // to account for rounding errors. - for (int y = 0; y < dest_height; y++) { - for (int x = 0; x < dest_width; x++) { - for (int channel = 0; channel < 4; channel++) { - int src_offset = (y * 2 * src_row_stride + x * 2 * 4) + channel; - int value = input[src_offset] + // Top left source pixel. - input[src_offset + 4] + // Top right source pixel. - input[src_offset + src_row_stride] + // Lower left. - input[src_offset + src_row_stride + 4]; // Lower right. - value /= 4; // Average. - int difference = value - output[(y * dest_width + x) * 4 + channel]; - EXPECT_TRUE(difference >= -1 || difference <= 1); - } - } - } -} - -} // namespace skia - diff --git a/skia/ext/image_operations.cc b/skia/ext/image_operations.cc deleted file mode 100644 index 9eab6e5..0000000 --- a/skia/ext/image_operations.cc +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -#define _USE_MATH_DEFINES -#include -#include -#include - -#include "skia/ext/image_operations.h" - -#include "base/gfx/rect.h" -#include "base/gfx/size.h" -#include "base/logging.h" -#include "base/stack_container.h" -#include "skia/ext/convolver.h" -#include "SkBitmap.h" - -// TODO(brettw) this should be removed when the base/gfx dependencies are -// removed. -using namespace gfx; - -namespace skia { - -namespace { - -// Returns the ceiling/floor as an integer. -inline int CeilInt(float val) { - return static_cast(ceil(val)); -} -inline int FloorInt(float val) { - return static_cast(floor(val)); -} - -// Filter function computation ------------------------------------------------- - -// Evaluates the box filter, which goes from -0.5 to +0.5. -float EvalBox(float x) { - return (x >= -0.5f && x < 0.5f) ? 1.0f : 0.0f; -} - -// Evaluates the Lanczos filter of the given filter size window for the given -// position. -// -// |filter_size| is the width of the filter (the "window"), outside of which -// the value of the function is 0. Inside of the window, the value is the -// normalized sinc function: -// lanczos(x) = sinc(x) * sinc(x / filter_size); -// where -// sinc(x) = sin(pi*x) / (pi*x); -float EvalLanczos(int filter_size, float x) { - if (x <= -filter_size || x >= filter_size) - return 0.0f; // Outside of the window. - if (x > -std::numeric_limits::epsilon() && - x < std::numeric_limits::epsilon()) - return 1.0f; // Special case the discontinuity at the origin. - float xpi = x * static_cast(M_PI); - return (sin(xpi) / xpi) * // sinc(x) - sin(xpi / filter_size) / (xpi / filter_size); // sinc(x/filter_size) -} - -// ResizeFilter ---------------------------------------------------------------- - -// Encapsulates computation and storage of the filters required for one complete -// resize operation. -class ResizeFilter { - public: - ResizeFilter(ImageOperations::ResizeMethod method, - const Size& src_full_size, - const Size& dest_size, - const Rect& dest_subset); - - // Returns the bounds in the input bitmap of data that is used in the output. - // The filter offsets are within this rectangle. - const Rect& src_depend() { return src_depend_; } - - // Returns the filled filter values. - const ConvolusionFilter1D& x_filter() { return x_filter_; } - const ConvolusionFilter1D& y_filter() { return y_filter_; } - - private: - // Returns the number of pixels that the filer spans, in filter space (the - // destination image). - float GetFilterSupport(float scale) { - switch (method_) { - case ImageOperations::RESIZE_BOX: - // The box filter just scales with the image scaling. - return 0.5f; // Only want one side of the filter = /2. - case ImageOperations::RESIZE_LANCZOS3: - // The lanczos filter takes as much space in the source image in - // each direction as the size of the window = 3 for Lanczos3. - return 3.0f; - default: - NOTREACHED(); - return 1.0f; - } - } - - // Computes one set of filters either horizontally or vertically. The caller - // will specify the "min" and "max" rather than the bottom/top and - // right/bottom so that the same code can be re-used in each dimension. - // - // |src_depend_lo| and |src_depend_size| gives the range for the source - // depend rectangle (horizontally or vertically at the caller's discretion - // -- see above for what this means). - // - // Likewise, the range of destination values to compute and the scale factor - // for the transform is also specified. - void ComputeFilters(int src_size, - int dest_subset_lo, int dest_subset_size, - float scale, float src_support, - ConvolusionFilter1D* output); - - // Computes the filter value given the coordinate in filter space. - inline float ComputeFilter(float pos) { - switch (method_) { - case ImageOperations::RESIZE_BOX: - return EvalBox(pos); - case ImageOperations::RESIZE_LANCZOS3: - return EvalLanczos(2, pos); - default: - NOTREACHED(); - return 0; - } - } - - ImageOperations::ResizeMethod method_; - - // Subset of source the filters will touch. - Rect src_depend_; - - // Size of the filter support on one side only in the destination space. - // See GetFilterSupport. - float x_filter_support_; - float y_filter_support_; - - // Subset of scaled destination bitmap to compute. - Rect out_bounds_; - - ConvolusionFilter1D x_filter_; - ConvolusionFilter1D y_filter_; - - DISALLOW_EVIL_CONSTRUCTORS(ResizeFilter); -}; - -ResizeFilter::ResizeFilter(ImageOperations::ResizeMethod method, - const Size& src_full_size, - const Size& dest_size, - const Rect& dest_subset) - : method_(method), - out_bounds_(dest_subset) { - float scale_x = static_cast(dest_size.width()) / - static_cast(src_full_size.width()); - float scale_y = static_cast(dest_size.height()) / - static_cast(src_full_size.height()); - - x_filter_support_ = GetFilterSupport(scale_x); - y_filter_support_ = GetFilterSupport(scale_y); - - gfx::Rect src_full(0, 0, src_full_size.width(), src_full_size.height()); - gfx::Rect dest_full(0, 0, - static_cast(src_full_size.width() * scale_x + 0.5), - static_cast(src_full_size.height() * scale_y + 0.5)); - - // Support of the filter in source space. - float src_x_support = x_filter_support_ / scale_x; - float src_y_support = y_filter_support_ / scale_y; - - ComputeFilters(src_full_size.width(), dest_subset.x(), dest_subset.width(), - scale_x, src_x_support, &x_filter_); - ComputeFilters(src_full_size.height(), dest_subset.y(), dest_subset.height(), - scale_y, src_y_support, &y_filter_); -} - -void ResizeFilter::ComputeFilters(int src_size, - int dest_subset_lo, int dest_subset_size, - float scale, float src_support, - ConvolusionFilter1D* output) { - int dest_subset_hi = dest_subset_lo + dest_subset_size; // [lo, hi) - - // When we're doing a magnification, the scale will be larger than one. This - // means the destination pixels are much smaller than the source pixels, and - // that the range covered by the filter won't necessarily cover any source - // pixel boundaries. Therefore, we use these clamped values (max of 1) for - // some computations. - float clamped_scale = std::min(1.0f, scale); - - // Speed up the divisions below by turning them into multiplies. - float inv_scale = 1.0f / scale; - - StackVector filter_values; - StackVector fixed_filter_values; - - // Loop over all pixels in the output range. We will generate one set of - // filter values for each one. Those values will tell us how to blend the - // source pixels to compute the destination pixel. - for (int dest_subset_i = dest_subset_lo; dest_subset_i < dest_subset_hi; - dest_subset_i++) { - // Reset the arrays. We don't declare them inside so they can re-use the - // same malloc-ed buffer. - filter_values->clear(); - fixed_filter_values->clear(); - - // This is the pixel in the source directly under the pixel in the dest. - float src_pixel = dest_subset_i * inv_scale; - - // Compute the (inclusive) range of source pixels the filter covers. - int src_begin = std::max(0, FloorInt(src_pixel - src_support)); - int src_end = std::min(src_size - 1, CeilInt(src_pixel + src_support)); - - // Compute the unnormalized filter value at each location of the source - // it covers. - float filter_sum = 0.0f; // Sub of the filter values for normalizing. - for (int cur_filter_pixel = src_begin; cur_filter_pixel <= src_end; - cur_filter_pixel++) { - // Distance from the center of the filter, this is the filter coordinate - // in source space. - float src_filter_pos = cur_filter_pixel - src_pixel; - - // Since the filter really exists in dest space, map it there. - float dest_filter_pos = src_filter_pos * clamped_scale; - - // Compute the filter value at that location. - float filter_value = ComputeFilter(dest_filter_pos); - filter_values->push_back(filter_value); - - filter_sum += filter_value; - } - DCHECK(!filter_values->empty()) << "We should always get a filter!"; - - // The filter must be normalized so that we don't affect the brightness of - // the image. Convert to normalized fixed point. - int16 fixed_sum = 0; - for (size_t i = 0; i < filter_values->size(); i++) { - int16 cur_fixed = output->FloatToFixed(filter_values[i] / filter_sum); - fixed_sum += cur_fixed; - fixed_filter_values->push_back(cur_fixed); - } - - // The conversion to fixed point will leave some rounding errors, which - // we add back in to avoid affecting the brightness of the image. We - // arbitrarily add this to the center of the filter array (this won't always - // be the center of the filter function since it could get clipped on the - // edges, but it doesn't matter enough to worry about that case). - int16 leftovers = output->FloatToFixed(1.0f) - fixed_sum; - fixed_filter_values[fixed_filter_values->size() / 2] += leftovers; - - // Now it's ready to go. - output->AddFilter(src_begin, &fixed_filter_values[0], - static_cast(fixed_filter_values->size())); - } -} - -} // namespace - -// Resize ---------------------------------------------------------------------- - -// static -SkBitmap ImageOperations::Resize(const SkBitmap& source, - ResizeMethod method, - const Size& dest_size, - const Rect& dest_subset) { - DCHECK(Rect(dest_size.width(), dest_size.height()).Contains(dest_subset)) << - "The supplied subset does not fall within the destination image."; - - // If the size of source or destination is 0, i.e. 0x0, 0xN or Nx0, just - // return empty - if (source.width() < 1 || source.height() < 1 || - dest_size.width() < 1 || dest_size.height() < 1) - return SkBitmap(); - - SkAutoLockPixels locker(source); - - ResizeFilter filter(method, Size(source.width(), source.height()), - dest_size, dest_subset); - - // Get a source bitmap encompassing this touched area. We construct the - // offsets and row strides such that it looks like a new bitmap, while - // referring to the old data. - const uint8* source_subset = - reinterpret_cast(source.getPixels()); - - // Convolve into the result. - SkBitmap result; - result.setConfig(SkBitmap::kARGB_8888_Config, - dest_subset.width(), dest_subset.height()); - result.allocPixels(); - BGRAConvolve2D(source_subset, static_cast(source.rowBytes()), - !source.isOpaque(), filter.x_filter(), filter.y_filter(), - static_cast(result.getPixels())); - - // Preserve the "opaque" flag for use as an optimization later. - result.setIsOpaque(source.isOpaque()); - - return result; -} - -// static -SkBitmap ImageOperations::Resize(const SkBitmap& source, - ResizeMethod method, - const Size& dest_size) { - Rect dest_subset(0, 0, dest_size.width(), dest_size.height()); - return Resize(source, method, dest_size, dest_subset); -} - -// static -SkBitmap ImageOperations::CreateBlendedBitmap(const SkBitmap& first, - const SkBitmap& second, - double alpha) { - DCHECK(alpha <= 1 && alpha >= 0); - DCHECK(first.width() == second.width()); - DCHECK(first.height() == second.height()); - DCHECK(first.bytesPerPixel() == second.bytesPerPixel()); - DCHECK(first.config() == SkBitmap::kARGB_8888_Config); - - // Optimize for case where we won't need to blend anything. - static const double alpha_min = 1.0 / 255; - static const double alpha_max = 254.0 / 255; - if (alpha < alpha_min) { - return first; - } else if (alpha > alpha_max) { - return second; - } - - SkAutoLockPixels lock_first(first); - SkAutoLockPixels lock_second(second); - - SkBitmap blended; - blended.setConfig(SkBitmap::kARGB_8888_Config, first.width(), - first.height(), 0); - blended.allocPixels(); - blended.eraseARGB(0, 0, 0, 0); - - double first_alpha = 1 - alpha; - - for (int y = 0; y < first.height(); y++) { - uint32* first_row = first.getAddr32(0, y); - uint32* second_row = second.getAddr32(0, y); - uint32* dst_row = blended.getAddr32(0, y); - - for (int x = 0; x < first.width(); x++) { - uint32 first_pixel = first_row[x]; - uint32 second_pixel = second_row[x]; - - int a = static_cast( - SkColorGetA(first_pixel) * first_alpha + - SkColorGetA(second_pixel) * alpha); - int r = static_cast( - SkColorGetR(first_pixel) * first_alpha + - SkColorGetR(second_pixel) * alpha); - int g = static_cast( - SkColorGetG(first_pixel) * first_alpha + - SkColorGetG(second_pixel) * alpha); - int b = static_cast( - SkColorGetB(first_pixel) * first_alpha + - SkColorGetB(second_pixel) * alpha); - - dst_row[x] = SkColorSetARGB(a, r, g, b); - } - } - - return blended; -} - -} // namespace skia - diff --git a/skia/ext/image_operations.h b/skia/ext/image_operations.h deleted file mode 100644 index 60a8da7c..0000000 --- a/skia/ext/image_operations.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SKIA_EXT_IMAGE_OPERATIONS_H_ -#define SKIA_EXT_IMAGE_OPERATIONS_H_ - -#include "base/basictypes.h" -#include "base/gfx/rect.h" - -class SkBitmap; - -namespace skia { - -class ImageOperations { - public: - enum ResizeMethod { - // Box filter. This is a weighted average of all of the pixels touching - // the destination pixel. For enlargement, this is nearest neighbor. - // - // You probably don't want this, it is here for testing since it is easy to - // compute. Use RESIZE_LANCZOS3 instead. - RESIZE_BOX, - - // 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, - }; - - // Resizes the given source bitmap using the specified resize method, so that - // the entire image is (dest_size) big. The dest_subset is the rectangle in - // this destination image that should actually be returned. - // - // The output image will be (dest_subset.width(), dest_subset.height()). This - // will save work if you do not need the entire bitmap. - // - // The destination subset must be smaller than the destination image. - static SkBitmap Resize(const SkBitmap& source, - ResizeMethod method, - const gfx::Size& dest_size, - const gfx::Rect& dest_subset); - - // Alternate version for resizing and returning the entire bitmap rather than - // a subset. - static SkBitmap Resize(const SkBitmap& source, - ResizeMethod method, - const gfx::Size& dest_size); - - - // Create a bitmap that is a blend of two others. The alpha argument - // specifies the opacity of the second bitmap. The provided bitmaps must - // use have the kARGB_8888_Config config and be of equal dimensions. - static SkBitmap CreateBlendedBitmap(const SkBitmap& first, - const SkBitmap& second, - double alpha); - private: - ImageOperations(); // Class for scoping only. -}; - -} // namespace skia - -#endif // SKIA_EXT_IMAGE_OPERATIONS_H_ - diff --git a/skia/ext/image_operations_unittest.cc b/skia/ext/image_operations_unittest.cc deleted file mode 100644 index 7a52d1f..0000000 --- a/skia/ext/image_operations_unittest.cc +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "skia/ext/image_operations.h" - -#include "testing/gtest/include/gtest/gtest.h" -#include "SkBitmap.h" - -namespace { - -// Computes the average pixel value for the given range, inclusive. -uint32_t AveragePixel(const SkBitmap& bmp, - int x_min, int x_max, - int y_min, int y_max) { - float accum[4] = {0, 0, 0, 0}; - int count = 0; - for (int y = y_min; y <= y_max; y++) { - for (int x = x_min; x <= x_max; x++) { - uint32_t cur = *bmp.getAddr32(x, y); - accum[0] += SkColorGetB(cur); - accum[1] += SkColorGetG(cur); - accum[2] += SkColorGetR(cur); - accum[3] += SkColorGetA(cur); - count++; - } - } - - return SkColorSetARGB(static_cast(accum[3] / count), - static_cast(accum[2] / count), - static_cast(accum[1] / count), - static_cast(accum[0] / count)); -} - -// Returns true if each channel of the given two colors are "close." This is -// used for comparing colors where rounding errors may cause off-by-one. -bool ColorsClose(uint32_t a, uint32_t b) { - return abs(static_cast(SkColorGetB(a) - SkColorGetB(b))) < 2 && - abs(static_cast(SkColorGetG(a) - SkColorGetG(b))) < 2 && - abs(static_cast(SkColorGetR(a) - SkColorGetR(b))) < 2 && - abs(static_cast(SkColorGetA(a) - SkColorGetA(b))) < 2; -} - -void FillDataToBitmap(int w, int h, SkBitmap* bmp) { - bmp->setConfig(SkBitmap::kARGB_8888_Config, w, h); - bmp->allocPixels(); - - unsigned char* src_data = - reinterpret_cast(bmp->getAddr32(0, 0)); - for (int i = 0; i < w * h; i++) { - src_data[i * 4 + 0] = static_cast(i % 255); - src_data[i * 4 + 1] = static_cast(i % 255); - src_data[i * 4 + 2] = static_cast(i % 255); - src_data[i * 4 + 3] = static_cast(i % 255); - } -} - -} // namespace - -// Makes the bitmap 50% the size as the original using a box filter. This is -// an easy operation that we can check the results for manually. -TEST(ImageOperations, Halve) { - // Make our source bitmap. - int src_w = 30, src_h = 38; - SkBitmap src; - FillDataToBitmap(src_w, src_h, &src); - - // Do a halving of the full bitmap. - SkBitmap actual_results = skia::ImageOperations::Resize( - src, skia::ImageOperations::RESIZE_BOX, gfx::Size(src_w / 2, src_h / 2)); - ASSERT_EQ(src_w / 2, actual_results.width()); - ASSERT_EQ(src_h / 2, actual_results.height()); - - // Compute the expected values & compare. - SkAutoLockPixels lock(actual_results); - for (int y = 0; y < actual_results.height(); y++) { - for (int x = 0; x < actual_results.width(); x++) { - int first_x = std::max(0, x * 2 - 1); - int last_x = std::min(src_w - 1, x * 2); - - int first_y = std::max(0, y * 2 - 1); - int last_y = std::min(src_h - 1, y * 2); - - uint32_t expected_color = AveragePixel(src, - first_x, last_x, first_y, last_y); - EXPECT_TRUE(ColorsClose(expected_color, *actual_results.getAddr32(x, y))); - } - } -} - -TEST(ImageOperations, HalveSubset) { - // Make our source bitmap. - int src_w = 16, src_h = 34; - SkBitmap src; - FillDataToBitmap(src_w, src_h, &src); - - // Do a halving of the full bitmap. - SkBitmap full_results = skia::ImageOperations::Resize( - src, skia::ImageOperations::RESIZE_BOX, gfx::Size(src_w / 2, src_h / 2)); - ASSERT_EQ(src_w / 2, full_results.width()); - ASSERT_EQ(src_h / 2, full_results.height()); - - // Now do a halving of a a subset, recall the destination subset is in the - // destination coordinate system (max = half of the original image size). - gfx::Rect subset_rect(2, 3, 3, 6); - SkBitmap subset_results = skia::ImageOperations::Resize( - src, skia::ImageOperations::RESIZE_BOX, - gfx::Size(src_w / 2, src_h / 2), subset_rect); - ASSERT_EQ(subset_rect.width(), subset_results.width()); - ASSERT_EQ(subset_rect.height(), subset_results.height()); - - // The computed subset and the corresponding subset of the original image - // should be the same. - SkAutoLockPixels full_lock(full_results); - SkAutoLockPixels subset_lock(subset_results); - for (int y = 0; y < subset_rect.height(); y++) { - for (int x = 0; x < subset_rect.width(); x++) { - ASSERT_EQ( - *full_results.getAddr32(x + subset_rect.x(), y + subset_rect.y()), - *subset_results.getAddr32(x, y)); - } - } -} - -// Resamples an iamge to the same image, it should give almost the same result. -TEST(ImageOperations, ResampleToSame) { - // Make our source bitmap. - int src_w = 16, src_h = 34; - SkBitmap src; - FillDataToBitmap(src_w, src_h, &src); - - // Do a resize of the full bitmap to the same size. The lanczos filter is good - // enough that we should get exactly the same image for output. - SkBitmap results = skia::ImageOperations::Resize( - src, skia::ImageOperations::RESIZE_LANCZOS3, gfx::Size(src_w, src_h)); - ASSERT_EQ(src_w, results.width()); - ASSERT_EQ(src_h, results.height()); - - SkAutoLockPixels src_lock(src); - SkAutoLockPixels results_lock(results); - for (int y = 0; y < src_h; y++) { - for (int x = 0; x < src_w; x++) { - EXPECT_EQ(*src.getAddr32(x, y), *results.getAddr32(x, y)); - } - } -} - diff --git a/skia/ext/platform_device_mac.cc b/skia/ext/platform_device_mac.cc index 3cc6fb4..9539e0f 100755 --- a/skia/ext/platform_device_mac.cc +++ b/skia/ext/platform_device_mac.cc @@ -5,7 +5,7 @@ #include "skia/ext/bitmap_platform_device_mac.h" #include "base/logging.h" -#include "skia/ext/skia_utils_mac.h" +#include "base/gfx/skia_utils_mac.h" #include "SkMatrix.h" #include "SkPath.h" #include "SkUtils.h" diff --git a/skia/ext/platform_device_win.cc b/skia/ext/platform_device_win.cc index 1e8301d..15201c0 100644 --- a/skia/ext/platform_device_win.cc +++ b/skia/ext/platform_device_win.cc @@ -5,14 +5,11 @@ #include "skia/ext/platform_device_win.h" #include "base/logging.h" +#include "base/gfx/skia_utils.h" #include "SkMatrix.h" #include "SkPath.h" #include "SkRegion.h" #include "SkUtils.h" -#include "skia/ext/skia_utils_win.h" - -// TODO(brettw) remove this when this file is converted to namespace skia. -using namespace skia; namespace gfx { diff --git a/skia/ext/skia_utils.cc b/skia/ext/skia_utils.cc deleted file mode 100644 index 651670e..0000000 --- a/skia/ext/skia_utils.cc +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "skia/ext/skia_utils_win.h" - -#include "SkRect.h" -#include "SkGradientShader.h" - -namespace skia { - -SkShader* CreateGradientShader(int start_point, - int end_point, - SkColor start_color, - SkColor end_color) { - SkColor grad_colors[2] = { start_color, end_color}; - SkPoint grad_points[2]; - grad_points[0].set(SkIntToScalar(0), SkIntToScalar(start_point)); - grad_points[1].set(SkIntToScalar(0), SkIntToScalar(end_point)); - - return SkGradientShader::CreateLinear( - grad_points, grad_colors, NULL, 2, SkShader::kRepeat_TileMode); -} - -} // namespace skia - diff --git a/skia/ext/skia_utils.h b/skia/ext/skia_utils.h deleted file mode 100644 index acfab28..0000000 --- a/skia/ext/skia_utils.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file contains cross-platform Skia helper routines. - -#ifndef SKIA_EXT_SKIA_UTILS_H_ -#define SKIA_EXT_SKIA_UTILS_H_ - -#include "SkShader.h" - -namespace skia { - -// Creates a vertical gradient shader. The caller owns the shader. -SkShader* CreateGradientShader(int start_point, - int end_point, - SkColor start_color, - SkColor end_color); - -} // namespace skia - -#endif // SKIA_EXT_SKIA_UTILS_H_ - diff --git a/skia/ext/skia_utils_mac.cc b/skia/ext/skia_utils_mac.cc deleted file mode 100644 index a7610aa..0000000 --- a/skia/ext/skia_utils_mac.cc +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "skia/ext/skia_utils_mac.h" - -#include "base/logging.h" -#include "SkMatrix.h" -#include "SkRect.h" - -namespace gfx { - -CGAffineTransform SkMatrixToCGAffineTransform(const SkMatrix& matrix) { - // CGAffineTransforms don't support perspective transforms, so make sure - // we don't get those. - DCHECK(matrix[SkMatrix::kMPersp0] == 0.0f); - DCHECK(matrix[SkMatrix::kMPersp1] == 0.0f); - DCHECK(matrix[SkMatrix::kMPersp2] == 1.0f); - - return CGAffineTransformMake(matrix[SkMatrix::kMScaleX], - matrix[SkMatrix::kMSkewY], - matrix[SkMatrix::kMSkewX], - matrix[SkMatrix::kMScaleY], - matrix[SkMatrix::kMTransX], - matrix[SkMatrix::kMTransY]); -} - -SkIRect CGRectToSkIRect(const CGRect& rect) { - SkIRect sk_rect = { - SkScalarRound(rect.origin.x), - SkScalarRound(rect.origin.y), - SkScalarRound(rect.origin.x + rect.size.width), - SkScalarRound(rect.origin.y + rect.size.height) - }; - return sk_rect; -} - -SkRect CGRectToSkRect(const CGRect& rect) { - SkRect sk_rect = { - rect.origin.x, - rect.origin.y, - rect.origin.x + rect.size.width, - rect.origin.y + rect.size.height, - }; - return sk_rect; -} - -CGRect SkIRectToCGRect(const SkIRect& rect) { - CGRect cg_rect = { - { rect.fLeft, rect.fTop }, - { rect.fRight - rect.fLeft, rect.fBottom - rect.fTop } - }; - return cg_rect; -} - -CGRect SkRectToCGRect(const SkRect& rect) { - CGRect cg_rect = { - { rect.fLeft, rect.fTop }, - { rect.fRight - rect.fLeft, rect.fBottom - rect.fTop } - }; - return cg_rect; -} - -// Converts CGColorRef to the ARGB layout Skia expects. -SkColor CGColorRefToSkColor(CGColorRef color) { - DCHECK(CGColorGetNumberOfComponents(color) == 4); - const CGFloat *components = CGColorGetComponents(color); - return SkColorSetARGB(SkScalarRound(255.0 * components[3]), // alpha - SkScalarRound(255.0 * components[0]), // red - SkScalarRound(255.0 * components[1]), // green - SkScalarRound(255.0 * components[2])); // blue -} - -// Converts ARGB to CGColorRef. -CGColorRef SkColorToCGColorRef(SkColor color) { - return CGColorCreateGenericRGB(SkColorGetR(color) / 255.0, - SkColorGetG(color) / 255.0, - SkColorGetB(color) / 255.0, - SkColorGetA(color) / 255.0); -} - -} // namespace gfx - diff --git a/skia/ext/skia_utils_mac.h b/skia/ext/skia_utils_mac.h deleted file mode 100644 index a99905f..0000000 --- a/skia/ext/skia_utils_mac.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - - -#ifndef BASE_GFX_SKIA_UTILS_MAC_H__ -#define BASE_GFX_SKIA_UTILS_MAC_H__ - -#include "SkColor.h" -#include - -struct SkMatrix; -struct SkIRect; -struct SkPoint; -struct SkRect; - -namespace gfx { - -// Converts a Skia point to a CoreGraphics CGPoint. -// Both use same in-memory format. -inline const CGPoint& SkPointToCGPoint(const SkPoint& point) { - return reinterpret_cast(point); -} - -// Converts a CoreGraphics point to a Skia CGPoint. -// Both use same in-memory format. -inline const SkPoint& CGPointToSkPoint(const CGPoint& point) { - return reinterpret_cast(point); -} - -// Matrix converters. -CGAffineTransform SkMatrixToCGAffineTransform(const SkMatrix& matrix); - -// Rectangle converters. -SkRect CGRectToSkRect(const CGRect& rect); -SkIRect CGRectToSkIRect(const CGRect& rect); - -// Converts a Skia rect to a CoreGraphics CGRect. -CGRect SkIRectToCGRect(const SkIRect& rect); -CGRect SkRectToCGRect(const SkRect& rect); - -// Converts CGColorRef to the ARGB layout Skia expects. -SkColor CGColorRefToSkColor(CGColorRef color); - -// Converts ARGB to CGColorRef. -CGColorRef SkColorToCGColorRef(SkColor color); - -} // namespace gfx - -#endif - diff --git a/skia/ext/skia_utils_win.cc b/skia/ext/skia_utils_win.cc deleted file mode 100644 index f695a63..0000000 --- a/skia/ext/skia_utils_win.cc +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "skia/ext/skia_utils_win.h" - -#include "SkRect.h" -#include "SkGradientShader.h" - -namespace { - -// Compiler assert from base/logging.h -template -struct CompileAssert { -}; -#undef COMPILE_ASSERT -#define COMPILE_ASSERT(expr, msg) \ - typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] - -COMPILE_ASSERT(SK_OFFSETOF(RECT, left) == SK_OFFSETOF(SkIRect, fLeft), o1); -COMPILE_ASSERT(SK_OFFSETOF(RECT, top) == SK_OFFSETOF(SkIRect, fTop), o2); -COMPILE_ASSERT(SK_OFFSETOF(RECT, right) == SK_OFFSETOF(SkIRect, fRight), o3); -COMPILE_ASSERT(SK_OFFSETOF(RECT, bottom) == SK_OFFSETOF(SkIRect, fBottom), o4); -COMPILE_ASSERT(sizeof(RECT().left) == sizeof(SkIRect().fLeft), o5); -COMPILE_ASSERT(sizeof(RECT().top) == sizeof(SkIRect().fTop), o6); -COMPILE_ASSERT(sizeof(RECT().right) == sizeof(SkIRect().fRight), o7); -COMPILE_ASSERT(sizeof(RECT().bottom) == sizeof(SkIRect().fBottom), o8); -COMPILE_ASSERT(sizeof(RECT) == sizeof(SkIRect), o9); - -} // namespace - -namespace skia { - -POINT SkPointToPOINT(const SkPoint& point) { - POINT win_point = { SkScalarRound(point.fX), SkScalarRound(point.fY) }; - return win_point; -} - -SkRect RECTToSkRect(const RECT& rect) { - SkRect sk_rect = { SkIntToScalar(rect.left), SkIntToScalar(rect.top), - SkIntToScalar(rect.right), SkIntToScalar(rect.bottom) }; - return sk_rect; -} - -SkColor COLORREFToSkColor(COLORREF color) { - return SkColorSetRGB(GetRValue(color), GetGValue(color), GetBValue(color)); -} - -COLORREF SkColorToCOLORREF(SkColor color) { - // Currently, Alpha is always 255 or the color is 0 so there is no need to - // demultiply the channels. If this is needed, (SkColorGetX(color) * 255 / a) - // will have to be added in the conversion. - return RGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color)); -} - -} // namespace skia - diff --git a/skia/ext/skia_utils_win.h b/skia/ext/skia_utils_win.h deleted file mode 100644 index 297608a..0000000 --- a/skia/ext/skia_utils_win.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SKIA_EXT_SKIA_UTILS_WIN_H_ -#define SKIA_EXT_SKIA_UTILS_WIN_H_ - -#include "SkColor.h" -#include "SkShader.h" - -struct SkIRect; -struct SkPoint; -struct SkRect; -typedef unsigned long DWORD; -typedef DWORD COLORREF; -typedef struct tagPOINT POINT; -typedef struct tagRECT RECT; - -namespace skia { - -// Converts a Skia point to a Windows POINT. -POINT SkPointToPOINT(const SkPoint& point); - -// Converts a Windows RECT to a Skia rect. -SkRect RECTToSkRect(const RECT& rect); - -// Converts a Windows RECT to a Skia rect. -// Both use same in-memory format. Verified by COMPILE_ASSERT() in -// skia_utils.cc. -inline const SkIRect& RECTToSkIRect(const RECT& rect) { - return reinterpret_cast(rect); -} - -// Converts a Skia rect to a Windows RECT. -// Both use same in-memory format. Verified by COMPILE_ASSERT() in -// skia_utils.cc. -inline const RECT& SkIRectToRECT(const SkIRect& rect) { - return reinterpret_cast(rect); -} - -// Creates a vertical gradient shader. The caller owns the shader. -SkShader* CreateGradientShader(int start_point, - int end_point, - SkColor start_color, - SkColor end_color); - -// Converts COLORREFs (0BGR) to the ARGB layout Skia expects. -SkColor COLORREFToSkColor(COLORREF color); - -// Converts ARGB to COLORREFs (0BGR). -COLORREF SkColorToCOLORREF(SkColor color); - -} // namespace skia - -#endif // SKIA_EXT_SKIA_UTILS_WIN_H_ - diff --git a/skia/ext/vector_device.cc b/skia/ext/vector_device.cc index 2dc0c30..a587e0c 100644 --- a/skia/ext/vector_device.cc +++ b/skia/ext/vector_device.cc @@ -5,13 +5,11 @@ #include "skia/ext/vector_device.h" #include "base/gfx/gdi_util.h" +#include "base/gfx/skia_utils.h" #include "base/logging.h" #include "base/scoped_handle.h" -#include "skia/ext/skia_utils_win.h" -#include "SkUtils.h" -// TOOD(brettw) remove this when this file is changed over to namespace skia. -using namespace skia; +#include "SkUtils.h" namespace gfx { diff --git a/skia/skia.vcproj b/skia/skia.vcproj index 65453c1..5e06d73 100644 --- a/skia/skia.vcproj +++ b/skia/skia.vcproj @@ -1321,22 +1321,6 @@ > - - - - - - - - @@ -1361,22 +1345,6 @@ > - - - - - - - - diff --git a/skia/skia.xcodeproj/project.pbxproj b/skia/skia.xcodeproj/project.pbxproj index 2fb458c..7ecdb3b 100644 --- a/skia/skia.xcodeproj/project.pbxproj +++ b/skia/skia.xcodeproj/project.pbxproj @@ -13,8 +13,6 @@ A70A3BAE0ED7385F00C31871 /* bitmap_platform_device_mac.cc in Sources */ = {isa = PBXBuildFile; fileRef = A70A3BA80ED7385F00C31871 /* bitmap_platform_device_mac.cc */; }; A70A3BAF0ED7385F00C31871 /* platform_canvas_mac.cc in Sources */ = {isa = PBXBuildFile; fileRef = A70A3BAA0ED7385F00C31871 /* platform_canvas_mac.cc */; }; A70A3BB00ED7385F00C31871 /* platform_device_mac.cc in Sources */ = {isa = PBXBuildFile; fileRef = A70A3BAC0ED7385F00C31871 /* platform_device_mac.cc */; }; - A74368350EE5C759003562CC /* skia_utils.cc in Sources */ = {isa = PBXBuildFile; fileRef = A74368310EE5C759003562CC /* skia_utils.cc */; }; - A74368360EE5C759003562CC /* skia_utils_mac.cc in Sources */ = {isa = PBXBuildFile; fileRef = A74368330EE5C759003562CC /* skia_utils_mac.cc */; }; E48EE4D20E34E873009DE966 /* Sk1DPathEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB4C46860DAE9C4F00FC0DB7 /* Sk1DPathEffect.cpp */; }; E48EE4D30E34E873009DE966 /* Sk2DPathEffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB4C46870DAE9C4F00FC0DB7 /* Sk2DPathEffect.cpp */; }; E48EE4D40E34E873009DE966 /* Sk64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB4C465C0DAE9C4A00FC0DB7 /* Sk64.cpp */; }; @@ -155,10 +153,6 @@ A70A3BAB0ED7385F00C31871 /* platform_canvas_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = platform_canvas_mac.h; path = ext/platform_canvas_mac.h; sourceTree = ""; }; A70A3BAC0ED7385F00C31871 /* platform_device_mac.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = platform_device_mac.cc; path = ext/platform_device_mac.cc; sourceTree = ""; }; A70A3BAD0ED7385F00C31871 /* platform_device_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = platform_device_mac.h; path = ext/platform_device_mac.h; sourceTree = ""; }; - A74368310EE5C759003562CC /* skia_utils.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = skia_utils.cc; path = ext/skia_utils.cc; sourceTree = ""; }; - A74368320EE5C759003562CC /* skia_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = skia_utils.h; path = ext/skia_utils.h; sourceTree = ""; }; - A74368330EE5C759003562CC /* skia_utils_mac.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = skia_utils_mac.cc; path = ext/skia_utils_mac.cc; sourceTree = ""; }; - A74368340EE5C759003562CC /* skia_utils_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = skia_utils_mac.h; path = ext/skia_utils_mac.h; sourceTree = ""; }; AB4C45B00DAE9C3700FC0DB7 /* SkTime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SkTime.cpp; sourceTree = ""; }; AB4C465C0DAE9C4A00FC0DB7 /* Sk64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Sk64.cpp; sourceTree = ""; }; AB4C465D0DAE9C4A00FC0DB7 /* SkBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SkBuffer.cpp; sourceTree = ""; }; @@ -500,10 +494,6 @@ A70A3BAB0ED7385F00C31871 /* platform_canvas_mac.h */, A70A3BAC0ED7385F00C31871 /* platform_device_mac.cc */, A70A3BAD0ED7385F00C31871 /* platform_device_mac.h */, - A74368310EE5C759003562CC /* skia_utils.cc */, - A74368320EE5C759003562CC /* skia_utils.h */, - A74368330EE5C759003562CC /* skia_utils_mac.cc */, - A74368340EE5C759003562CC /* skia_utils_mac.h */, ); name = ext; sourceTree = ""; @@ -1049,8 +1039,6 @@ E48EE5380E34E873009DE966 /* SkUtils.cpp in Sources */, E48EE5390E34E873009DE966 /* SkWriter32.cpp in Sources */, E48EE53A0E34E873009DE966 /* SkXfermode.cpp in Sources */, - A74368350EE5C759003562CC /* skia_utils.cc in Sources */, - A74368360EE5C759003562CC /* skia_utils_mac.cc in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/webkit/port/platform/graphics/FontWin.cpp b/webkit/port/platform/graphics/FontWin.cpp index 0fa5a26..ac28623 100644 --- a/webkit/port/platform/graphics/FontWin.cpp +++ b/webkit/port/platform/graphics/FontWin.cpp @@ -35,8 +35,8 @@ #include "SkiaUtils.h" #include "UniscribeHelperTextRun.h" +#include "base/gfx/skia_utils.h" // TODO(brettw) remove this dependency. #include "skia/ext/platform_canvas_win.h" -#include "skia/ext/skia_utils_win.h" namespace WebCore { @@ -69,7 +69,7 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color)); - SetTextColor(hdc, skia::SkColorToCOLORREF(color)); + SetTextColor(hdc, gfx::SkColorToCOLORREF(color)); SetBkMode(hdc, TRANSPARENT); // Windows needs the characters and the advances in nice contiguous @@ -168,7 +168,7 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color)); - SetTextColor(hdc, skia::SkColorToCOLORREF(color)); + SetTextColor(hdc, gfx::SkColorToCOLORREF(color)); SetBkMode(hdc, TRANSPARENT); // Uniscribe counts the coordinates from the upper left, while WebKit uses diff --git a/webkit/port/platform/graphics/ImageSkia.cpp b/webkit/port/platform/graphics/ImageSkia.cpp index 12d5ae9..cfdc739 100644 --- a/webkit/port/platform/graphics/ImageSkia.cpp +++ b/webkit/port/platform/graphics/ImageSkia.cpp @@ -43,7 +43,7 @@ #include "SkiaUtils.h" #include "SkShader.h" -#include "skia/ext/image_operations.h" +#include "base/gfx/image_operations.h" // TODO(brettw) remove this dependency. #include "skia/ext/platform_canvas.h" namespace WebCore { @@ -217,8 +217,8 @@ void drawResampledBitmap(SkCanvas& canvas, destBitmapSubsetSkI.height()); // Resample the needed part of the image. - SkBitmap resampled = skia::ImageOperations::Resize(subset, - skia::ImageOperations::RESIZE_LANCZOS3, + SkBitmap resampled = gfx::ImageOperations::Resize(subset, + gfx::ImageOperations::RESIZE_LANCZOS3, gfx::Size(destRectRounded.width(), destRectRounded.height()), destBitmapSubset); @@ -350,8 +350,8 @@ void Image::drawPattern(GraphicsContext* context, if (resampling == RESAMPLE_AWESOME) { // Do nice resampling. - SkBitmap resampled = skia::ImageOperations::Resize(src_subset, - skia::ImageOperations::RESIZE_LANCZOS3, + SkBitmap resampled = gfx::ImageOperations::Resize(src_subset, + gfx::ImageOperations::RESIZE_LANCZOS3, gfx::Size(static_cast(dest_bitmap_width), static_cast(dest_bitmap_height))); shader = SkShader::CreateBitmapShader( diff --git a/webkit/port/platform/graphics/NativeImageSkia.cpp b/webkit/port/platform/graphics/NativeImageSkia.cpp index 7158d06..fb765eb 100644 --- a/webkit/port/platform/graphics/NativeImageSkia.cpp +++ b/webkit/port/platform/graphics/NativeImageSkia.cpp @@ -28,11 +28,11 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "config.h" -#include "NativeImageSkia.h" -#include "SkiaUtils.h" +#include "base/gfx/image_operations.h" -#include "skia/ext/image_operations.h" +#include "NativeImageSkia.h" +#include "SkiaUtils.h" NativeImageSkia::NativeImageSkia() : SkBitmap(), @@ -61,8 +61,8 @@ bool NativeImageSkia::hasResizedBitmap(int w, int h) const { SkBitmap NativeImageSkia::resizedBitmap(int w, int h) const { if (m_resizedImage.width() != w || m_resizedImage.height() != h) { - m_resizedImage = skia::ImageOperations::Resize(*this, - skia::ImageOperations::RESIZE_LANCZOS3, gfx::Size(w, h)); + m_resizedImage = gfx::ImageOperations::Resize(*this, + gfx::ImageOperations::RESIZE_LANCZOS3, gfx::Size(w, h)); } return m_resizedImage; } diff --git a/webkit/port/platform/graphics/PlatformContextSkia.cpp b/webkit/port/platform/graphics/PlatformContextSkia.cpp index 1c63927..06b3c0a 100644 --- a/webkit/port/platform/graphics/PlatformContextSkia.cpp +++ b/webkit/port/platform/graphics/PlatformContextSkia.cpp @@ -34,6 +34,8 @@ #include "SkiaUtils.h" #include "wtf/MathExtras.h" +#include "base/gfx/image_operations.h" // TODO(brettw) remove this depencency. +#include "base/gfx/skia_utils.h" // TODO(brettw) remove this depencency. #include "skia/ext/platform_canvas.h" #include "SkBitmap.h" diff --git a/webkit/port/rendering/RenderThemeWin.cpp b/webkit/port/rendering/RenderThemeWin.cpp index 48a8947..907a6e4 100644 --- a/webkit/port/rendering/RenderThemeWin.cpp +++ b/webkit/port/rendering/RenderThemeWin.cpp @@ -37,8 +37,9 @@ #include "SkiaUtils.h" #include "ThemeHelperWin.h" -#include "base/gfx/native_theme.h" // TODO(brettw) fix this dependency. -#include "base/win_util.h" // TODO(brettw) fix this dependency. +#include "base/gfx/native_theme.h" +#include "base/gfx/skia_utils.h" +#include "base/win_util.h" namespace { @@ -571,7 +572,7 @@ bool RenderThemeWin::paintTextFieldInternal(RenderObject* o, gfx::PlatformCanvas* canvas = helper.context()->platformContext()->canvas(); HDC hdc = canvas->beginPlatformPaint(); - COLORREF clr = o->style()->backgroundColor().rgb() & 0xFFFFFF; + COLORREF clr = gfx::SkColorToCOLORREF(o->style()->backgroundColor().rgb()); RECT renderRect = helper.rect(); gfx::NativeTheme::instance()->PaintTextField(hdc, diff --git a/webkit/tools/test_shell/test_shell_tests.vcproj b/webkit/tools/test_shell/test_shell_tests.vcproj index cebf759..4f6a036 100644 --- a/webkit/tools/test_shell/test_shell_tests.vcproj +++ b/webkit/tools/test_shell/test_shell_tests.vcproj @@ -307,10 +307,6 @@ > - - @@ -343,10 +339,6 @@ > - - -- cgit v1.1