1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef SKIA_EXT_PLATFORM_CANVAS_H_
6#define SKIA_EXT_PLATFORM_CANVAS_H_
7
8// The platform-specific device will include the necessary platform headers
9// to get the surface type.
10#include "base/basictypes.h"
11#include "skia/ext/platform_device.h"
12#include "skia/ext/refptr.h"
13#include "third_party/skia/include/core/SkBitmap.h"
14#include "third_party/skia/include/core/SkCanvas.h"
15#include "third_party/skia/include/core/SkPixelRef.h"
16
17namespace skia {
18
19typedef SkCanvas PlatformCanvas;
20
21//
22//  Note about error handling.
23//
24//  Creating a canvas can fail at times, most often because we fail to allocate
25//  the backing-store (pixels). This can be from out-of-memory, or something
26//  more opaque, like GDI or cairo reported a failure.
27//
28//  To allow the caller to handle the failure, every Create... factory takes an
29//  enum as its last parameter. The default value is kCrashOnFailure. If the
30//  caller passes kReturnNullOnFailure, then the caller is responsible to check
31//  the return result.
32//
33enum OnFailureType {
34  CRASH_ON_FAILURE,
35  RETURN_NULL_ON_FAILURE
36};
37
38#if defined(WIN32)
39  // The shared_section parameter is passed to gfx::PlatformDevice::create.
40  // See it for details.
41  SK_API SkCanvas* CreatePlatformCanvas(int width,
42                                        int height,
43                                        bool is_opaque,
44                                        HANDLE shared_section,
45                                        OnFailureType failure_type);
46#elif defined(__APPLE__)
47  SK_API SkCanvas* CreatePlatformCanvas(CGContextRef context,
48                                        int width,
49                                        int height,
50                                        bool is_opaque,
51                                        OnFailureType failure_type);
52
53  SK_API SkCanvas* CreatePlatformCanvas(int width,
54                                        int height,
55                                        bool is_opaque,
56                                        uint8_t* context,
57                                        OnFailureType failure_type);
58#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
59      defined(__sun) || defined(ANDROID)
60  // Linux ---------------------------------------------------------------------
61
62  // Construct a canvas from the given memory region. The memory is not cleared
63  // first. @data must be, at least, @height * StrideForWidth(@width) bytes.
64  SK_API SkCanvas* CreatePlatformCanvas(int width,
65                                        int height,
66                                        bool is_opaque,
67                                        uint8_t* data,
68                                        OnFailureType failure_type);
69#endif
70
71static inline SkCanvas* CreatePlatformCanvas(int width,
72                                             int height,
73                                             bool is_opaque) {
74  return CreatePlatformCanvas(width, height, is_opaque, 0, CRASH_ON_FAILURE);
75}
76
77SK_API SkCanvas* CreateCanvas(const skia::RefPtr<SkBaseDevice>& device,
78                              OnFailureType failure_type);
79
80static inline SkCanvas* CreateBitmapCanvas(int width,
81                                           int height,
82                                           bool is_opaque) {
83  return CreatePlatformCanvas(width, height, is_opaque, 0, CRASH_ON_FAILURE);
84}
85
86static inline SkCanvas* TryCreateBitmapCanvas(int width,
87                                              int height,
88                                              bool is_opaque) {
89  return CreatePlatformCanvas(width, height, is_opaque, 0,
90                              RETURN_NULL_ON_FAILURE);
91}
92
93// Return the stride (length of a line in bytes) for the given width. Because
94// we use 32-bits per pixel, this will be roughly 4*width. However, for
95// alignment reasons we may wish to increase that.
96SK_API size_t PlatformCanvasStrideForWidth(unsigned width);
97
98// Returns the SkBaseDevice pointer of the topmost rect with a non-empty
99// clip. In practice, this is usually either the top layer or nothing, since
100// we usually set the clip to new layers when we make them.
101//
102// This may return NULL, so callers need to check.
103//
104// This is different than SkCanvas' getDevice, because that returns the
105// bottommost device.
106//
107// Danger: the resulting device should not be saved. It will be invalidated
108// by the next call to save() or restore().
109SK_API SkBaseDevice* GetTopDevice(const SkCanvas& canvas);
110
111// Returns true if native platform routines can be used to draw on the
112// given canvas. If this function returns false, BeginPlatformPaint will
113// return NULL PlatformSurface.
114SK_API bool SupportsPlatformPaint(const SkCanvas* canvas);
115
116// Draws into the a native platform surface, |context|.  Forwards to
117// DrawToNativeContext on a PlatformDevice instance bound to the top device.
118// If no PlatformDevice instance is bound, is a no-operation.
119SK_API void DrawToNativeContext(SkCanvas* canvas,
120                                PlatformSurface context,
121                                int x,
122                                int y,
123                                const PlatformRect* src_rect);
124
125// Sets the opacity of each pixel in the specified region to be opaque.
126SK_API void MakeOpaque(SkCanvas* canvas, int x, int y, int width, int height);
127
128// These calls should surround calls to platform drawing routines, the
129// surface returned here can be used with the native platform routines.
130//
131// Call EndPlatformPaint when you are done and want to use skia operations
132// after calling the platform-specific BeginPlatformPaint; this will
133// synchronize the bitmap to OS if necessary.
134SK_API PlatformSurface BeginPlatformPaint(SkCanvas* canvas);
135SK_API void EndPlatformPaint(SkCanvas* canvas);
136
137// Helper class for pairing calls to BeginPlatformPaint and EndPlatformPaint.
138// Upon construction invokes BeginPlatformPaint, and upon destruction invokes
139// EndPlatformPaint.
140class SK_API ScopedPlatformPaint {
141 public:
142  explicit ScopedPlatformPaint(SkCanvas* canvas) : canvas_(canvas) {
143    platform_surface_ = BeginPlatformPaint(canvas);
144  }
145  ~ScopedPlatformPaint() { EndPlatformPaint(canvas_); }
146
147  // Returns the PlatformSurface to use for native platform drawing calls.
148  PlatformSurface GetPlatformSurface() { return platform_surface_; }
149 private:
150  SkCanvas* canvas_;
151  PlatformSurface platform_surface_;
152
153  // Disallow copy and assign
154  ScopedPlatformPaint(const ScopedPlatformPaint&);
155  ScopedPlatformPaint& operator=(const ScopedPlatformPaint&);
156};
157
158// PlatformBitmap holds a PlatformSurface that can also be used as an SkBitmap.
159class SK_API PlatformBitmap {
160 public:
161  PlatformBitmap();
162  ~PlatformBitmap();
163
164  // Returns true if the bitmap was able to allocate its surface.
165  bool Allocate(int width, int height, bool is_opaque);
166
167  // Returns the platform surface, or 0 if Allocate() did not return true.
168  PlatformSurface GetSurface() { return surface_; }
169
170  // Return the skia bitmap, which will be empty if Allocate() did not
171  // return true.
172  //
173  // The resulting SkBitmap holds a refcount on the underlying platform surface,
174  // so the surface will remain allocated so long as the SkBitmap or its copies
175  // stay around.
176  const SkBitmap& GetBitmap() { return bitmap_; }
177
178 private:
179  SkBitmap bitmap_;
180  PlatformSurface surface_;  // initialized to 0
181  intptr_t platform_extra_;  // platform specific, initialized to 0
182
183  DISALLOW_COPY_AND_ASSIGN(PlatformBitmap);
184};
185
186}  // namespace skia
187
188#endif  // SKIA_EXT_PLATFORM_CANVAS_H_
189