diff options
author | tschmelcher@chromium.org <tschmelcher@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-26 18:58:42 +0000 |
---|---|---|
committer | tschmelcher@chromium.org <tschmelcher@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-26 18:58:42 +0000 |
commit | 864e1b6cae0e473fc086d8c7e7a9287856dcd6a2 (patch) | |
tree | fec68fd585b551eb3950c13b44f29c6817702a77 /o3d | |
parent | d847eff0a268df958e6b4c72cb826e5fd1e28383 (diff) | |
download | chromium_src-864e1b6cae0e473fc086d8c7e7a9287856dcd6a2.zip chromium_src-864e1b6cae0e473fc086d8c7e7a9287856dcd6a2.tar.gz chromium_src-864e1b6cae0e473fc086d8c7e7a9287856dcd6a2.tar.bz2 |
O2D: Fix graphical artifacting with transparent images caused by using non-premultiplied alpha ARGB images as if they were premultiplied alpha ARGB. This caused the transparent parts of images to be too bright (and in some cases fully opaque). Cairo only supports premultiplied alpha, but O3D calls SetRect() with non-premultiplied alpha, so we have to convert.
TEST=loaded O2D and verified transparent images look correct now
BUG=none
Review URL: http://codereview.chromium.org/6309007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@72658 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r-- | o3d/core/cross/cairo/texture_cairo.cc | 87 | ||||
-rw-r--r-- | o3d/core/cross/cairo/texture_cairo.h | 5 |
2 files changed, 49 insertions, 43 deletions
diff --git a/o3d/core/cross/cairo/texture_cairo.cc b/o3d/core/cross/cairo/texture_cairo.cc index 476988e..7cb8864 100644 --- a/o3d/core/cross/cairo/texture_cairo.cc +++ b/o3d/core/cross/cairo/texture_cairo.cc @@ -1,5 +1,5 @@ /* - * Copyright 2010, Google Inc. + * Copyright 2011, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,6 +34,9 @@ // Texture Class for handling Cairo Rendering Mode. #include "core/cross/cairo/texture_cairo.h" + +#include <string.h> + #include "core/cross/cairo/renderer_cairo.h" namespace o3d { @@ -62,7 +65,6 @@ static int CairoFormatFromO3DFormat( TextureCairo::TextureCairo(ServiceLocator* service_locator, cairo_surface_t* image_surface, - cairo_t* image_surface_context, Texture::Format format, int levels, int width, @@ -76,8 +78,7 @@ TextureCairo::TextureCairo(ServiceLocator* service_locator, enable_render_surfaces), renderer_(static_cast<RendererCairo*>( service_locator->GetService<Renderer>())), - image_surface_(image_surface), - image_surface_context_(image_surface_context) { + image_surface_(image_surface) { DLOG(INFO) << "Texture2D Construct"; DCHECK_NE(format, Texture::UNKNOWN_FORMAT); } @@ -91,7 +92,6 @@ TextureCairo* TextureCairo::Create(ServiceLocator* service_locator, bool enable_render_surfaces) { int cairo_format = CairoFormatFromO3DFormat(format); cairo_surface_t* image_surface; - cairo_t* image_surface_context; cairo_status_t status; if (-1 == cairo_format) { DLOG(ERROR) << "Texture format " << format << " not supported by Cairo"; @@ -106,27 +106,15 @@ TextureCairo* TextureCairo::Create(ServiceLocator* service_locator, DLOG(ERROR) << "Error creating Cairo image surface: " << status; goto fail1; } - image_surface_context = cairo_create(image_surface); - status = cairo_status(image_surface_context); - if (CAIRO_STATUS_SUCCESS != status) { - DLOG(ERROR) << "Error creating Cairo image surface draw context: " - << status; - goto fail2; - } - - cairo_set_operator(image_surface_context, CAIRO_OPERATOR_SOURCE); return new TextureCairo(service_locator, image_surface, - image_surface_context, format, levels, width, height, enable_render_surfaces); - fail2: - cairo_destroy(image_surface_context); fail1: cairo_surface_destroy(image_surface); fail0: @@ -140,7 +128,6 @@ const Texture::RGBASwizzleIndices& TextureCairo::GetABGR32FSwizzleIndices() { } TextureCairo::~TextureCairo() { - cairo_destroy(image_surface_context_); cairo_surface_destroy(image_surface_); renderer_ = NULL; DLOG(INFO) << "Texture2DCairo Destruct"; @@ -152,7 +139,7 @@ void TextureCairo::SetRect(int level, unsigned dst_top, unsigned src_width, unsigned src_height, - const void* src_data, + const void* src_data_void, int src_pitch) { DLOG(INFO) << "Texture2DCairo SetRect"; @@ -161,26 +148,48 @@ void TextureCairo::SetRect(int level, return; } - // Create image surface to represent the source. - cairo_surface_t* source_image_surface = cairo_image_surface_create_for_data( - const_cast<unsigned char*>( - static_cast<const unsigned char*>(src_data)), - cairo_image_surface_get_format(image_surface_), - src_width, - src_height, - src_pitch); - - // Set that surface as the source for paint operations to our texture. - cairo_set_source_surface(image_surface_context_, - source_image_surface, - dst_left, - dst_top); - - // Paint to the texture. This copies the data. - cairo_paint(image_surface_context_); - - // Discard our reference to the source surface. - cairo_surface_destroy(source_image_surface); + cairo_surface_flush(image_surface_); + + const unsigned char* src_data = reinterpret_cast<const unsigned char*>( + src_data_void); + + unsigned char* dst_data = cairo_image_surface_get_data(image_surface_); + + int dst_pitch = cairo_image_surface_get_stride(image_surface_); + + dst_data += dst_top * dst_pitch + dst_left * 4; + + if (ARGB8 == format()) { + // Cairo supports only premultiplied alpha, but we get the images as + // non-premultiplied alpha, so we have to convert. + for (unsigned i = 0; i < src_height; ++i) { + for (unsigned j = 0; j < src_width; ++j) { + // NOTE: This assumes a little-endian architecture (e.g., x86). It works + // for RGBA or BGRA where alpha is in byte 3. + // Get alpha. + uint8 alpha = src_data[3]; + // Convert each colour. + for (int i = 0; i < 3; i++) { + dst_data[i] = (src_data[i] * alpha + 128U) / 255U; + } + // Copy alpha. + dst_data[3] = alpha; + src_data += 4; + dst_data += 4; + } + src_data += src_pitch - src_width * 4; + dst_data += dst_pitch - src_width * 4; + } + } else { + // Just copy the data. + for (unsigned i = 0; i < src_height; ++i) { + memcpy(dst_data, src_data, src_width * 4); + src_data += src_pitch; + dst_data += dst_pitch; + } + } + + cairo_surface_mark_dirty(image_surface_); TextureUpdated(); } diff --git a/o3d/core/cross/cairo/texture_cairo.h b/o3d/core/cross/cairo/texture_cairo.h index 19aa09c..786d090 100644 --- a/o3d/core/cross/cairo/texture_cairo.h +++ b/o3d/core/cross/cairo/texture_cairo.h @@ -1,5 +1,5 @@ /* - * Copyright 2010, Google Inc. + * Copyright 2011, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -99,7 +99,6 @@ class TextureCairo : public Texture2D { // Initializes the Texture2D. TextureCairo(ServiceLocator* service_locator, cairo_surface_t* image_surface, - cairo_t* image_surface_context, Texture::Format format, int levels, int width, @@ -110,8 +109,6 @@ class TextureCairo : public Texture2D { RendererCairo* renderer_; // The Cairo image for this texture. cairo_surface_t* image_surface_; - // A Cairo drawing context for updating this image. - cairo_t* image_surface_context_; }; } // namespace o2d |