1 // Copyright (c) 2013 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.
7 #include "ppapi/c/pp_errors.h"
8 #include "ppapi/cpp/completion_callback.h"
9 #include "ppapi/cpp/graphics_2d.h"
10 #include "ppapi/cpp/image_data.h"
11 #include "ppapi/cpp/input_event.h"
12 #include "ppapi/cpp/instance.h"
13 #include "ppapi/cpp/module.h"
14 #include "ppapi/cpp/rect.h"
15 #include "ppapi/cpp/var.h"
16 #include "ppapi/utility/completion_callback_factory.h"
18 // When compiling natively on Windows, PostMessage can be #define-d to
24 // Example plugin to demonstrate usage of pp::View and pp::Graphics2D APIs for
25 // rendering 2D graphics at device resolution. See Paint() for more details.
26 class MyInstance
: public pp::Instance
{
28 explicit MyInstance(PP_Instance instance
)
29 : pp::Instance(instance
),
36 using_device_pixels_(true) {
37 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE
|
38 PP_INPUTEVENT_CLASS_KEYBOARD
);
41 virtual void DidChangeView(const pp::View
& view
) {
42 pp::Rect view_rect
= view
.GetRect();
43 if (view_rect
.width() == width_
&&
44 view_rect
.height() == height_
&&
45 view
.GetDeviceScale() == device_scale_
&&
46 view
.GetCSSScale() == css_scale_
)
47 return; // We don't care about the position, only the size and scale.
49 width_
= view_rect
.width();
50 height_
= view_rect
.height();
51 device_scale_
= view
.GetDeviceScale();
52 css_scale_
= view
.GetCSSScale();
54 pixel_width_
= width_
* device_scale_
;
55 pixel_height_
= height_
* device_scale_
;
60 virtual bool HandleInputEvent(const pp::InputEvent
& event
) {
61 switch (event
.GetType()) {
62 case PP_INPUTEVENT_TYPE_MOUSEDOWN
:
63 HandleMouseDown(event
);
70 virtual void HandleMessage(const pp::Var
& message_data
) {
71 if (message_data
.is_string()) {
72 std::string str
= message_data
.AsString();
74 if (using_device_pixels_
) {
75 using_device_pixels_
= false;
78 } else if (str
== "device") {
79 if (!using_device_pixels_
) {
80 using_device_pixels_
= true;
83 } else if (str
== "metrics") {
84 std::stringstream stream
;
85 stream
<< "DIP (" << width_
<< ", " << height_
<< "), device pixels=("
86 << pixel_width_
<< ", " << pixel_height_
<<"), device_scale="
87 << device_scale_
<<", css_scale=" << css_scale_
;
88 PostMessage(stream
.str());
94 void HandleMouseDown(const pp::InputEvent
& event
) {
95 pp::MouseInputEvent
mouse_event(event
);
96 pp::Point
position(mouse_event
.GetPosition());
97 pp::Point
position_device(position
.x() * device_scale_
,
98 position
.y() * device_scale_
);
99 std::stringstream stream
;
100 stream
<< "Mousedown at DIP (" << position
.x() << ", " << position
.y()
101 << "), device pixel (" << position_device
.x() << ", "
102 << position_device
.y() << ")";
103 if (css_scale_
> 0.0f
) {
104 pp::Point
position_css(position
.x() / css_scale_
,
105 position
.y() / css_scale_
);
106 stream
<< ", CSS pixel (" << position_css
.x() << ", " << position_css
.y()
109 stream
<<", unknown CSS pixel. css_scale_=" << css_scale_
;
111 PostMessage(stream
.str());
114 void SetupGraphics() {
115 if (using_device_pixels_
) {
116 // The plugin will treat 1 pixel in the device context as 1 device pixel.
117 // This will set up a properly-sized pp::Graphics2D, and tell Pepper
118 // to apply the correct scale so the resulting concatenated scale leaves
119 // each pixel in the device context as one on the display device.
120 device_context_
= pp::Graphics2D(this,
121 pp::Size(pixel_width_
, pixel_height_
),
123 if (device_scale_
> 0.0f
) {
124 // If SetScale is promoted to pp::Graphics2D, the dc_dev constructor
125 // can be removed, and this will become the following line instead.
126 // device_context_.SetScale(1.0f / device_scale_);
127 device_context_
.SetScale(1.0f
/ device_scale_
);
130 // The plugin will treat 1 pixel in the device context as one DIP.
131 device_context_
= pp::Graphics2D(this, pp::Size(width_
, height_
), true);
133 BindGraphics(device_context_
);
138 int width
= using_device_pixels_
? pixel_width_
: width_
;
139 int height
= using_device_pixels_
? pixel_height_
: height_
;
140 pp::ImageData
image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
141 pp::Size(width
, height
), false);
145 // Painting here will demonstrate a few techniques:
146 // - painting a thin blue box and cross-hatch to show the finest resolution
148 // - painting a 25 DIP (logical pixel) green circle to show how objects of a
149 // fixed size in DIPs should be scaled if using a high-resolution
151 // - paiting a 50 CSS pixel red circle to show how objects of a fixed size
152 // in CSS pixels should be scaled if using a high-resolution
153 // pp::Graphics2D, as well as how to use the GetCSSScale value properly.
155 // Painting in "DIP resolution" mode (|using_device_pixels_| false) will
156 // demonstrate how unscaled graphics would look, even on a high-DPI device.
157 // Painting in "device resolution" mode (|using_device_pixels_| true) will
158 // show how scaled graphics would look crisper on a high-DPI device, in
159 // comparison to using unscaled graphics. Both modes should look identical
160 // when displayed on a non-high-DPI device (window.devicePixelRatio == 1).
161 // Toggling between "DIP resolution" mode and "device resolution" mode
162 // should not change the sizes of the circles.
164 // Changing the browser zoom level should cause the CSS circle to zoom, but
165 // not the DIP-sized circle.
167 // All painting here does not use any anti-aliasing.
168 float circle_1_radius
= 25;
169 if (using_device_pixels_
)
170 circle_1_radius
*= device_scale_
;
172 float circle_2_radius
= 50 * css_scale_
;
173 if (using_device_pixels_
)
174 circle_2_radius
*= device_scale_
;
176 for (int y
= 0; y
< height
; ++y
) {
177 char* row
= static_cast<char*>(image
.data()) + (y
* image
.stride());
178 uint32_t* pixel
= reinterpret_cast<uint32_t*>(row
);
179 for (int x
= 0; x
< width
; ++x
) {
180 int dx
= (width
/ 2) - x
;
181 int dy
= (height
/ 2) - y
;
182 float dist_squared
= (dx
* dx
) + (dy
* dy
);
183 if (x
== 0 || y
== 0 || x
== width
- 1 || y
== width
- 1 || x
== y
||
184 width
- x
- 1 == y
) {
185 *pixel
++ = 0xFF0000FF;
186 } else if (dist_squared
< circle_1_radius
* circle_1_radius
) {
187 *pixel
++ = 0xFF00FF00;
188 } else if (dist_squared
< circle_2_radius
* circle_2_radius
) {
189 *pixel
++ = 0xFFFF0000;
191 *pixel
++ = 0xFF000000;
196 device_context_
.ReplaceContents(&image
);
197 device_context_
.Flush(pp::CompletionCallback(&OnFlush
, this));
200 static void OnFlush(void* user_data
, int32_t result
) {}
202 pp::Graphics2D device_context_
;
209 bool using_device_pixels_
;
212 // This object is the global object representing this plugin library as long as
214 class MyModule
: public pp::Module
{
216 MyModule() : pp::Module() {}
217 virtual ~MyModule() {}
219 // Override CreateInstance to create your customized Instance object.
220 virtual pp::Instance
* CreateInstance(PP_Instance instance
) {
221 return new MyInstance(instance
);
227 // Factory function for your specialization of the Module object.
228 Module
* CreateModule() {
229 return new MyModule();