// Copyright (c) 2011 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_CANVAS_PAINT_LINUX_H_ #define SKIA_EXT_CANVAS_PAINT_LINUX_H_ #include "base/logging.h" #include "skia/ext/canvas_paint_common.h" #include "skia/ext/platform_canvas.h" #include namespace skia { // A class designed to translate skia painting into a region in a GdkWindow. // On construction, it will set up a context for painting into, and on // destruction, it will commit it to the GdkWindow. // Note: The created context is always inialized to (0, 0, 0, 0). template class CanvasPaintT : public T { public: // This constructor assumes the result is opaque. explicit CanvasPaintT(GdkEventExpose* event) : context_(NULL), window_(event->window), region_(gdk_region_copy(event->region)), composite_alpha_(false) { init(true); } CanvasPaintT(GdkEventExpose* event, bool opaque) : context_(NULL), window_(event->window), region_(gdk_region_copy(event->region)), composite_alpha_(false) { init(opaque); } virtual ~CanvasPaintT() { if (!is_empty()) { GetPlatformCanvas(this)->restoreToCount(1); // Blit the dirty rect to the window. CHECK(window_); cairo_t* cr = gdk_cairo_create(window_); CHECK(cr); if (composite_alpha_) cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_surface_t* source_surface = cairo_get_target(context_); CHECK(source_surface); // Flush cairo's cache of the surface. cairo_surface_mark_dirty(source_surface); GdkRectangle bounds = rectangle(); cairo_set_source_surface(cr, source_surface, bounds.x, bounds.y); gdk_cairo_region(cr, region_); cairo_fill(cr); cairo_destroy(cr); } gdk_region_destroy(region_); } // Sets whether the bitmap is composited in such a way that the alpha channel // is honored. This is only useful if you've enabled an RGBA colormap on the // widget. The default is false. void set_composite_alpha(bool composite_alpha) { composite_alpha_ = composite_alpha; } // Returns true if the invalid region is empty. The caller should call this // function to determine if anything needs painting. bool is_empty() const { return gdk_region_empty(region_); } GdkRectangle rectangle() const { GdkRectangle bounds; gdk_region_get_clipbox(region_, &bounds); return bounds; } private: void init(bool opaque) { GdkRectangle bounds = rectangle(); PlatformCanvas* canvas = GetPlatformCanvas(this); if (!canvas->initialize(bounds.width, bounds.height, opaque, NULL)) { // Cause a deliberate crash; CHECK(false); } // No need to clear the canvas, because cairo automatically performs the // clear. // Need to translate so that the dirty region appears at the origin of the // surface. canvas->translate(-SkIntToScalar(bounds.x), -SkIntToScalar(bounds.y)); context_ = BeginPlatformPaint(canvas); } cairo_t* context_; GdkWindow* window_; GdkRegion* region_; // See description above setter. bool composite_alpha_; // Disallow copy and assign. CanvasPaintT(const CanvasPaintT&); CanvasPaintT& operator=(const CanvasPaintT&); }; typedef CanvasPaintT PlatformCanvasPaint; } // namespace skia #endif // SKIA_EXT_CANVAS_PAINT_LINUX_H_