summaryrefslogtreecommitdiffstats
path: root/skia/ext/platform_canvas_linux.h
blob: 47e8162aeed438b8aff5dcee0a599a6bf258a6da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// 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_PLATFORM_CANVAS_LINUX_H_
#define SKIA_EXT_PLATFORM_CANVAS_LINUX_H_

#include <unistd.h>

#include "skia/ext/platform_device_linux.h"

#include <cairo/cairo.h>
#include <gdk/gdk.h>

namespace skia {

// This class is a specialization of the regular SkCanvas that is designed to
// work with a gfx::PlatformDevice to manage platform-specific drawing. It
// allows using both Skia operations and platform-specific operations.
class PlatformCanvasLinux : public SkCanvas {
 public:
  // Set is_opaque if you are going to erase the bitmap and not use
  // tranparency: this will enable some optimizations.  The shared_section
  // parameter is passed to gfx::PlatformDevice::create.  See it for details.
  //
  // If you use the version with no arguments, you MUST call initialize()
  PlatformCanvasLinux();
  PlatformCanvasLinux(int width, int height, bool is_opaque);
  // Construct a canvas from the given memory region. The memory is not cleared
  // first. @data must be, at least, @height * StrideForWidth(@width) bytes.
  PlatformCanvasLinux(int width, int height, bool is_opaque, uint8_t* data);
  virtual ~PlatformCanvasLinux();

  // For two-part init, call if you use the no-argument constructor above
  bool initialize(int width, int height, bool is_opaque);
  bool initialize(int width, int height, bool is_opaque, uint8_t* data);

  // These calls should surround calls to platform-specific drawing routines.
  // The cairo_surface_t* returned by beginPlatformPaint represents the
  // memory that can be used to draw into.
  // endPlatformPaint is a no-op; it is used for symmetry with Windows.
  cairo_surface_t* beginPlatformPaint();
  void endPlatformPaint() {}

  // Returns the platform device pointer of the topmost rect with a non-empty
  // clip. Both the windows and mac versions have an equivalent of this method;
  // a Linux version is added for compatibility.
  PlatformDeviceLinux& getTopPlatformDevice() const;

  // Return the stride (length of a line in bytes) for the given width. Because
  // we use 32-bits per pixel, this will be roughly 4*width. However, for
  // alignment reasons we may wish to increase that.
  static size_t StrideForWidth(unsigned width);

 protected:
  // Creates a device store for use by the canvas. We override this so that
  // the device is always our own so we know that we can use GDI operations
  // on it. Simply calls into createPlatformDevice().
  virtual SkDevice* createDevice(SkBitmap::Config, int width, int height,
                                 bool is_opaque, bool isForLayer);

  // Creates a device store for use by the canvas. By default, it creates a
  // BitmapPlatformDevice object. Can be overridden to change the object type.
  virtual SkDevice* createPlatformDevice(int width, int height, bool is_opaque);

  // Disallow copy and assign.
  PlatformCanvasLinux(const PlatformCanvasLinux&);
  PlatformCanvasLinux& operator=(const PlatformCanvasLinux&);
};

// A class designed to translate skia painting into a region in a
// GdkWindow. This class has been adapted from the class with the same name in
// platform_canvas_win.h. On construction, it will set up a context for
// painting into, and on destruction, it will commit it to the GdkWindow.
template <class T>
class CanvasPaintT : public T {
 public:
  explicit CanvasPaintT(GdkEventExpose* event)
      : surface_(NULL),
        window_(event->window),
        rectangle_(event->area),
        composite_alpha_(false) {
    init(true);
  }

  CanvasPaintT(GdkEventExpose* event, bool opaque)
      : surface_(NULL),
        window_(event->window),
        rectangle_(event->area),
        composite_alpha_(false) {
    init(opaque);
  }

  virtual ~CanvasPaintT() {
    if (!isEmpty()) {
      T::restoreToCount(1);

      // Blit the dirty rect to the window.
      cairo_t* cr = gdk_cairo_create(window_);
      if (composite_alpha_)
        cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
      cairo_set_source_surface(cr, surface_, rectangle_.x, rectangle_.y);
      cairo_rectangle(cr, rectangle_.x, rectangle_.y,
                      rectangle_.width, rectangle_.height);
      cairo_fill(cr);
      cairo_destroy(cr);
    }
  }

  // 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 isEmpty() const {
    return rectangle_.width == 0 || rectangle_.height == 0;
  }

  const GdkRectangle& rectangle() const {
    return rectangle_;
  }

 private:
  void init(bool opaque) {
    if (!T::initialize(rectangle_.width, rectangle_.height, opaque, NULL)) {
      // Cause a deliberate crash;
      *(char*) 0 = 0;
    }

    // Need to translate so that the dirty region appears at the origin of the
    // surface.
    T::translate(-SkIntToScalar(rectangle_.x), -SkIntToScalar(rectangle_.y));

    surface_ = T::getTopPlatformDevice().beginPlatformPaint();
  }

  cairo_surface_t* surface_;
  GdkWindow* window_;
  GdkRectangle rectangle_;
  // See description above setter.
  bool composite_alpha_;

  // Disallow copy and assign.
  CanvasPaintT(const CanvasPaintT&);
  CanvasPaintT& operator=(const CanvasPaintT&);
};

}  // namespace skia

#endif  // SKIA_EXT_PLATFORM_CANVAS_LINUX_H_