diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-29 18:17:04 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-29 18:17:04 +0000 |
commit | 2caf4d005cb3b86b61ae559f08f2493e19129e3f (patch) | |
tree | 95e9eb1d2ec77fc179f5fdc26573db1449a5afb4 /gfx | |
parent | 797794bd42c10ff1dfecc25f91ec32a17d991b15 (diff) | |
download | chromium_src-2caf4d005cb3b86b61ae559f08f2493e19129e3f.zip chromium_src-2caf4d005cb3b86b61ae559f08f2493e19129e3f.tar.gz chromium_src-2caf4d005cb3b86b61ae559f08f2493e19129e3f.tar.bz2 |
Add support for Radial Gradient Brush and Bitmap Brush to gfx::Canvas.
BUG=none
TEST=see unittest
Review URL: http://codereview.chromium.org/3058012
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@54148 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gfx')
-rw-r--r-- | gfx/canvas.h | 34 | ||||
-rw-r--r-- | gfx/canvas_direct2d.cc | 93 | ||||
-rw-r--r-- | gfx/canvas_direct2d.h | 11 | ||||
-rw-r--r-- | gfx/canvas_direct2d_unittest.cc | 60 | ||||
-rw-r--r-- | gfx/canvas_skia.cc | 34 | ||||
-rw-r--r-- | gfx/canvas_skia.h | 11 | ||||
-rw-r--r-- | gfx/gfx.gyp | 49 |
7 files changed, 274 insertions, 18 deletions
diff --git a/gfx/canvas.h b/gfx/canvas.h index 52857a4..6b59c6d 100644 --- a/gfx/canvas.h +++ b/gfx/canvas.h @@ -207,9 +207,9 @@ class Canvas { // |positions| is a list of positions corresponding to the color stops, an // array of floats of increasing value ranging from 0.0f to 1.0f. // |position_count| is the size of the |colors| and |positions| arrays. - // |tile_mode| - // Returns an encapsulated platform shader object which the caller must - // delete. + // |tile_mode| specifies how the gradient brush repeats outside its natural + // bounds. + // Returns an encapsulated platform brush object which the caller must delete. virtual Brush* CreateLinearGradientBrush( const gfx::Point& start_point, const gfx::Point& end_point, @@ -218,6 +218,34 @@ class Canvas { size_t position_count, TileMode tile_mode) = 0; + // Creates a radial gradient brush. + // |center_point| is the center of the circle in the brush's coordinate space. + // |radius| is the radius of the circle. + // |colors| is a list of color stops. + // |positions| is a list of positions corresponding to the color stops, an + // array of floats of increasing value ranging from 0.0f to 1.0f. + // |position_count| is the size of the |colors| and |positions| arrays. + // |tile_mode| specifies how the gradient brush repeats outside its natural + // bounds. + // Returns an encapsulated platform brush object which the caller must delete. + virtual Brush* CreateRadialGradientBrush( + const gfx::Point& center_point, + float radius, + const SkColor colors[], + const float positions[], + size_t position_count, + TileMode tile_mode) = 0; + + // Creates a bitmap brush. + // |bitmap| is the bitmap to be used for the brush. + // |tile_mode_x,y| - specifies how the brush tiles the areas beyond those + // filled by its bitmap along each axis. + // Returns an encapsulated platform brush object which the caller must delete. + virtual Brush* CreateBitmapBrush( + const SkBitmap& bitmap, + TileMode tile_mode_x, + TileMode tile_mode_y) = 0; + // TODO(beng): remove this once we don't need to use any skia-specific methods // through this interface. // A quick and dirty way to obtain the underlying SkCanvas. diff --git a/gfx/canvas_direct2d.cc b/gfx/canvas_direct2d.cc index e18272c..406078d 100644 --- a/gfx/canvas_direct2d.cc +++ b/gfx/canvas_direct2d.cc @@ -4,6 +4,7 @@ #include "gfx/canvas_direct2d.h" +#include "base/scoped_ptr.h" #include "gfx/rect.h" namespace { @@ -44,6 +45,28 @@ D2D1_EXTEND_MODE TileModeToExtendMode(gfx::Canvas::TileMode tile_mode) { return D2D1_EXTEND_MODE_CLAMP; } +ID2D1GradientStopCollection* CreateGradientStopCollection( + ID2D1RenderTarget* render_target, + const SkColor colors[], + const float positions[], + size_t position_count, + gfx::Canvas::TileMode tile_mode) { + scoped_array<D2D1_GRADIENT_STOP> gradient_stops( + new D2D1_GRADIENT_STOP[position_count]); + for (size_t i = 0; i < position_count; ++i) { + gradient_stops[i].color = SkColorToColorF(colors[i]); + gradient_stops[i].position = positions[i]; + } + ID2D1GradientStopCollection* gradient_stop_collection = NULL; + HRESULT hr = render_target->CreateGradientStopCollection( + gradient_stops.get(), + position_count, + D2D1_GAMMA_2_2, + TileModeToExtendMode(tile_mode), + &gradient_stop_collection); + return SUCCEEDED(hr) ? gradient_stop_collection : NULL; +} + // A platform wrapper for a Direct2D brush that makes sure the underlying // ID2D1Brush COM object is released when this object is destroyed. class Direct2DBrush : public gfx::Brush { @@ -280,28 +303,70 @@ Brush* CanvasDirect2D::CreateLinearGradientBrush( const float positions[], size_t position_count, TileMode tile_mode) { - ID2D1GradientStopCollection* gradient_stop_collection = NULL; - D2D1_GRADIENT_STOP* gradient_stops = new D2D1_GRADIENT_STOP[position_count]; - for (size_t i = 0; i < position_count; ++i) { - gradient_stops[i].color = SkColorToColorF(colors[i]); - gradient_stops[i].position = positions[i]; - } - HRESULT hr = rt_->CreateGradientStopCollection(gradient_stops, - position_count, - D2D1_GAMMA_2_2, - TileModeToExtendMode(tile_mode), - &gradient_stop_collection); - if (FAILED(hr)) + ScopedComPtr<ID2D1GradientStopCollection> gradient_stop_collection( + CreateGradientStopCollection(rt_, colors, positions, position_count, + tile_mode)); + if (!gradient_stop_collection.get()) return NULL; ID2D1LinearGradientBrush* brush = NULL; - hr = rt_->CreateLinearGradientBrush( + HRESULT hr = rt_->CreateLinearGradientBrush( D2D1::LinearGradientBrushProperties(PointToPoint2F(start_point), PointToPoint2F(end_point)), gradient_stop_collection, &brush); + return SUCCEEDED(hr) ? new Direct2DBrush(brush) : NULL; +} + +Brush* CanvasDirect2D::CreateRadialGradientBrush( + const gfx::Point& center_point, + float radius, + const SkColor colors[], + const float positions[], + size_t position_count, + TileMode tile_mode) { + ScopedComPtr<ID2D1GradientStopCollection> gradient_stop_collection( + CreateGradientStopCollection(rt_, colors, positions, position_count, + tile_mode)); + if (!gradient_stop_collection.get()) + return NULL; - return new Direct2DBrush(brush); + ID2D1RadialGradientBrush* brush = NULL; + HRESULT hr = rt_->CreateRadialGradientBrush( + D2D1::RadialGradientBrushProperties(PointToPoint2F(center_point), + PointToPoint2F(gfx::Point()), + radius, + radius), + gradient_stop_collection, + &brush); + return SUCCEEDED(hr) ? new Direct2DBrush(brush) : NULL; +} + +Brush* CanvasDirect2D::CreateBitmapBrush( + const SkBitmap& bitmap, + TileMode tile_mode_x, + TileMode tile_mode_y) { + ScopedComPtr<ID2D1Bitmap> d2d1_bitmap; + HRESULT hr = rt_->CreateBitmap( + D2D1::SizeU(bitmap.width(), bitmap.height()), + NULL, + NULL, + D2D1::BitmapProperties( + D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, + D2D1_ALPHA_MODE_IGNORE)), + d2d1_bitmap.Receive()); + bitmap.lockPixels(); + d2d1_bitmap->CopyFromMemory(NULL, bitmap.getPixels(), bitmap.rowBytes()); + bitmap.unlockPixels(); + + ID2D1BitmapBrush* brush = NULL; + hr = rt_->CreateBitmapBrush( + d2d1_bitmap, + D2D1::BitmapBrushProperties(TileModeToExtendMode(tile_mode_x), + TileModeToExtendMode(tile_mode_y)), + D2D1::BrushProperties(), + &brush); + return SUCCEEDED(hr) ? new Direct2DBrush(brush) : NULL; } CanvasSkia* CanvasDirect2D::AsCanvasSkia() { diff --git a/gfx/canvas_direct2d.h b/gfx/canvas_direct2d.h index 7ff973b..4cd5cd4 100644 --- a/gfx/canvas_direct2d.h +++ b/gfx/canvas_direct2d.h @@ -75,6 +75,17 @@ class CanvasDirect2D : public Canvas { const float positions[], size_t position_count, TileMode tile_mode); + virtual Brush* CreateRadialGradientBrush( + const gfx::Point& center_point, + float radius, + const SkColor colors[], + const float positions[], + size_t position_count, + TileMode tile_mode); + virtual Brush* CreateBitmapBrush( + const SkBitmap& bitmap, + TileMode tile_mode_x, + TileMode tile_mode_y); virtual CanvasSkia* AsCanvasSkia(); virtual const CanvasSkia* AsCanvasSkia() const; diff --git a/gfx/canvas_direct2d_unittest.cc b/gfx/canvas_direct2d_unittest.cc index d8c02c1..ff63302 100644 --- a/gfx/canvas_direct2d_unittest.cc +++ b/gfx/canvas_direct2d_unittest.cc @@ -8,13 +8,18 @@ #include <vssym32.h> #include "base/command_line.h" +#include "base/ref_counted_memory.h" +#include "base/resource_util.h" #include "base/scoped_ptr.h" #include "gfx/canvas_direct2d.h" #include "gfx/canvas_skia.h" +#include "gfx/codec/png_codec.h" #include "gfx/native_theme_win.h" #include "gfx/window_impl.h" +#include "grit/gfx_resources.h" #include "testing/gtest/include/gtest/gtest.h" + namespace { class TestWindow : public gfx::WindowImpl { @@ -71,6 +76,27 @@ class TestWindow : public gfx::WindowImpl { // static const wchar_t* TestWindow::kVisibleModeFlag = L"d2d-canvas-visible"; +// Loads a png data blob from the data resources associated with this +// executable, decodes it and returns a SkBitmap. +SkBitmap LoadBitmapFromResources(int resource_id) { + SkBitmap bitmap; + + HINSTANCE resource_instance = _AtlBaseModule.GetResourceInstance(); + void* data_ptr; + size_t data_size; + if (base::GetDataResourceFromModule(resource_instance, resource_id, &data_ptr, + &data_size)) { + scoped_refptr<RefCountedMemory> memory(new RefCountedStaticMemory( + reinterpret_cast<const unsigned char*>(data_ptr), data_size)); + if (!memory) + return bitmap; + + if (!gfx::PNGCodec::Decode(memory->front(), memory->size(), &bitmap)) + NOTREACHED() << "Unable to decode theme image resource " << resource_id; + } + return bitmap; +} + } // namespace TEST(CanvasDirect2D, CreateCanvas) { @@ -221,3 +247,37 @@ TEST(CanvasDirect2D, CreateLinearGradientBrush) { canvas.FillRectInt(brush.get(), 0, 0, 500, 500); canvas.Restore(); } + +TEST(CanvasDirect2D, CreateRadialGradientBrush) { + TestWindow window; + gfx::CanvasDirect2D canvas(window.rt()); + + canvas.Save(); + SkColor colors[] = { SK_ColorBLUE, SK_ColorGREEN }; + float positions[] = { 0.0f, 1.0f }; + scoped_ptr<gfx::Brush> brush(canvas.CreateRadialGradientBrush( + gfx::Point(200, 200), + 100.0f, + colors, + positions, + 2, + gfx::Canvas::TileMode_Clamp)); + canvas.FillRectInt(brush.get(), 0, 0, 500, 500); + canvas.Restore(); +} + +TEST(CanvasDirect2D, CreateBitmapBrush) { + TestWindow window; + gfx::CanvasDirect2D canvas(window.rt()); + + SkBitmap bitmap = LoadBitmapFromResources(IDR_BITMAP_BRUSH_IMAGE); + + canvas.Save(); + scoped_ptr<gfx::Brush> brush(canvas.CreateBitmapBrush( + bitmap, + gfx::Canvas::TileMode_Mirror, + gfx::Canvas::TileMode_Mirror)); + canvas.FillRectInt(brush.get(), 0, 0, 500, 500); + canvas.Restore(); +} + diff --git a/gfx/canvas_skia.cc b/gfx/canvas_skia.cc index fbdc0a9..f2c344c 100644 --- a/gfx/canvas_skia.cc +++ b/gfx/canvas_skia.cc @@ -18,6 +18,12 @@ namespace { +SkPoint PointToSkPoint(const gfx::Point point) { + SkPoint sk_point; + sk_point.set(SkIntToScalar(point.x()), SkIntToScalar(point.y())); + return sk_point; +} + SkShader::TileMode TileModeToSkShaderTileMode(gfx::Canvas::TileMode tile_mode) { switch (tile_mode) { case gfx::Canvas::TileMode_Clamp: @@ -364,6 +370,34 @@ Brush* CanvasSkia::CreateLinearGradientBrush( return new SkiaShader(shader); } +Brush* CanvasSkia::CreateRadialGradientBrush( + const gfx::Point& center_point, + float radius, + const SkColor colors[], + const float positions[], + size_t position_count, + TileMode tile_mode) { + SkShader* shader = SkGradientShader::CreateRadial( + PointToSkPoint(center_point), + radius, + colors, + positions, + position_count, + TileModeToSkShaderTileMode(tile_mode)); + return new SkiaShader(shader); +} + +Brush* CanvasSkia::CreateBitmapBrush( + const SkBitmap& bitmap, + TileMode tile_mode_x, + TileMode tile_mode_y) { + SkShader* shader = SkShader::CreateBitmapShader( + bitmap, + TileModeToSkShaderTileMode(tile_mode_x), + TileModeToSkShaderTileMode(tile_mode_y)); + return new SkiaShader(shader); +} + CanvasSkia* CanvasSkia::AsCanvasSkia() { return this; } diff --git a/gfx/canvas_skia.h b/gfx/canvas_skia.h index 5187ad6..71fbb42 100644 --- a/gfx/canvas_skia.h +++ b/gfx/canvas_skia.h @@ -131,6 +131,17 @@ class CanvasSkia : public skia::PlatformCanvas, const float positions[], size_t position_count, TileMode tile_mode); + virtual Brush* CreateRadialGradientBrush( + const gfx::Point& center_point, + float radius, + const SkColor colors[], + const float positions[], + size_t position_count, + TileMode tile_mode); + virtual Brush* CreateBitmapBrush( + const SkBitmap& bitmap, + TileMode tile_mode_x, + TileMode tile_mode_y); virtual CanvasSkia* AsCanvasSkia(); virtual const CanvasSkia* AsCanvasSkia() const; diff --git a/gfx/gfx.gyp b/gfx/gfx.gyp index e3eeb66..5947c4a 100644 --- a/gfx/gfx.gyp +++ b/gfx/gfx.gyp @@ -5,6 +5,9 @@ { 'variables': { 'chromium_code': 1, + 'grit_info_cmd': ['python', '../tools/grit/grit_info.py'], + 'grit_cmd': ['python', '../tools/grit/grit.py'], + 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/gfx', }, 'targets': [ { @@ -13,6 +16,7 @@ 'msvs_guid': 'C8BD2821-EAE5-4AC6-A0E4-F82CAC2956CC', 'dependencies': [ 'gfx', + 'gfx_resources', '../skia/skia.gyp:skia', '../testing/gtest.gyp:gtest', ], @@ -27,6 +31,7 @@ 'run_all_unittests.cc', 'skbitmap_operations_unittest.cc', 'test_suite.h', + '<(SHARED_INTERMEDIATE_DIR)/gfx/gfx_resources.rc', ], 'include_dirs': [ '..', @@ -155,7 +160,49 @@ ], }], ], - }, + }, + { + # theme_resources also generates a .cc file, so it can't use the rules above. + 'target_name': 'gfx_resources', + 'type': 'none', + 'msvs_guid' : '5738AE53-E919-4987-A2EF-15FDBD8F90F6', + 'actions': [ + { + 'action_name': 'gfx_resources', + 'variables': { + 'input_path': 'gfx_resources.grd', + }, + 'inputs': [ + '<!@(<(grit_info_cmd) --inputs <(input_path))', + ], + 'outputs': [ + '<!@(<(grit_info_cmd) --outputs \'<(grit_out_dir)\' <(input_path))', + ], + 'action': [ + '<@(grit_cmd)', + '-i', '<(input_path)', 'build', + '-o', '<(grit_out_dir)', + ], + 'conditions': [ + ['use_titlecase_in_grd_files==1', { + 'action': ['-D', 'use_titlecase'], + }], + ], + 'message': 'Generating resources from <(input_path)', + }, + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '<(grit_out_dir)', + ], + }, + 'conditions': [ + ['OS=="win"', { + 'dependencies': ['../build/win/system.gyp:cygwin'], + }], + ], + }, + ], } |