Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ppapi / examples / scaling / scaling.cc
blob6a7c4ebb08b19007f2085eccf80664ceea68074a
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.
5 #include <sstream>
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
19 // something else.
20 #ifdef PostMessage
21 #undef PostMessage
22 #endif
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 {
27 public:
28 explicit MyInstance(PP_Instance instance)
29 : pp::Instance(instance),
30 width_(0),
31 height_(0),
32 pixel_width_(0),
33 pixel_height_(0),
34 device_scale_(1.0f),
35 css_scale_(1.0f),
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_ = static_cast<int>(width_ * device_scale_);
55 pixel_height_ = static_cast<int>(height_ * device_scale_);
57 SetupGraphics();
60 virtual bool HandleInputEvent(const pp::InputEvent& event) {
61 switch (event.GetType()) {
62 case PP_INPUTEVENT_TYPE_MOUSEDOWN:
63 HandleMouseDown(event);
64 return true;
65 default:
66 return false;
70 virtual void HandleMessage(const pp::Var& message_data) {
71 if (message_data.is_string()) {
72 std::string str = message_data.AsString();
73 if (str == "dip") {
74 if (using_device_pixels_) {
75 using_device_pixels_ = false;
76 SetupGraphics();
78 } else if (str == "device") {
79 if (!using_device_pixels_) {
80 using_device_pixels_ = true;
81 SetupGraphics();
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());
93 private:
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(
98 static_cast<int32_t>(position.x() * device_scale_),
99 static_cast<int32_t>(position.y() * device_scale_));
100 std::stringstream stream;
101 stream << "Mousedown at DIP (" << position.x() << ", " << position.y()
102 << "), device pixel (" << position_device.x() << ", "
103 << position_device.y() << ")";
104 if (css_scale_ > 0.0f) {
105 pp::Point position_css(static_cast<int32_t>(position.x() / css_scale_),
106 static_cast<int32_t>(position.y() / css_scale_));
107 stream << ", CSS pixel (" << position_css.x() << ", " << position_css.y()
108 <<")";
109 } else {
110 stream <<", unknown CSS pixel. css_scale_=" << css_scale_;
112 PostMessage(stream.str());
115 void SetupGraphics() {
116 if (using_device_pixels_) {
117 // The plugin will treat 1 pixel in the device context as 1 device pixel.
118 // This will set up a properly-sized pp::Graphics2D, and tell Pepper
119 // to apply the correct scale so the resulting concatenated scale leaves
120 // each pixel in the device context as one on the display device.
121 device_context_ = pp::Graphics2D(this,
122 pp::Size(pixel_width_, pixel_height_),
123 true);
124 if (device_scale_ > 0.0f) {
125 // If SetScale is promoted to pp::Graphics2D, the dc_dev constructor
126 // can be removed, and this will become the following line instead.
127 // device_context_.SetScale(1.0f / device_scale_);
128 device_context_.SetScale(1.0f / device_scale_);
130 } else {
131 // The plugin will treat 1 pixel in the device context as one DIP.
132 device_context_ = pp::Graphics2D(this, pp::Size(width_, height_), true);
134 BindGraphics(device_context_);
135 Paint();
138 void Paint() {
139 int width = using_device_pixels_ ? pixel_width_ : width_;
140 int height = using_device_pixels_ ? pixel_height_ : height_;
141 pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
142 pp::Size(width, height), false);
143 if (image.is_null())
144 return;
146 // Painting here will demonstrate a few techniques:
147 // - painting a thin blue box and cross-hatch to show the finest resolution
148 // available.
149 // - painting a 25 DIP (logical pixel) green circle to show how objects of a
150 // fixed size in DIPs should be scaled if using a high-resolution
151 // pp::Graphics2D.
152 // - paiting a 50 CSS pixel red circle to show how objects of a fixed size
153 // in CSS pixels should be scaled if using a high-resolution
154 // pp::Graphics2D, as well as how to use the GetCSSScale value properly.
156 // Painting in "DIP resolution" mode (|using_device_pixels_| false) will
157 // demonstrate how unscaled graphics would look, even on a high-DPI device.
158 // Painting in "device resolution" mode (|using_device_pixels_| true) will
159 // show how scaled graphics would look crisper on a high-DPI device, in
160 // comparison to using unscaled graphics. Both modes should look identical
161 // when displayed on a non-high-DPI device (window.devicePixelRatio == 1).
162 // Toggling between "DIP resolution" mode and "device resolution" mode
163 // should not change the sizes of the circles.
165 // Changing the browser zoom level should cause the CSS circle to zoom, but
166 // not the DIP-sized circle.
168 // All painting here does not use any anti-aliasing.
169 float circle_1_radius = 25;
170 if (using_device_pixels_)
171 circle_1_radius *= device_scale_;
173 float circle_2_radius = 50 * css_scale_;
174 if (using_device_pixels_)
175 circle_2_radius *= device_scale_;
177 for (int y = 0; y < height; ++y) {
178 char* row = static_cast<char*>(image.data()) + (y * image.stride());
179 uint32_t* pixel = reinterpret_cast<uint32_t*>(row);
180 for (int x = 0; x < width; ++x) {
181 int dx = (width / 2) - x;
182 int dy = (height / 2) - y;
183 float dist_squared = static_cast<float>((dx * dx) + (dy * dy));
184 if (x == 0 || y == 0 || x == width - 1 || y == width - 1 || x == y ||
185 width - x - 1 == y) {
186 *pixel++ = 0xFF0000FF;
187 } else if (dist_squared < circle_1_radius * circle_1_radius) {
188 *pixel++ = 0xFF00FF00;
189 } else if (dist_squared < circle_2_radius * circle_2_radius) {
190 *pixel++ = 0xFFFF0000;
191 } else {
192 *pixel++ = 0xFF000000;
197 device_context_.ReplaceContents(&image);
198 device_context_.Flush(pp::CompletionCallback(&OnFlush, this));
201 static void OnFlush(void* user_data, int32_t result) {}
203 pp::Graphics2D device_context_;
204 int width_;
205 int height_;
206 int pixel_width_;
207 int pixel_height_;
208 float device_scale_;
209 float css_scale_;
210 bool using_device_pixels_;
213 // This object is the global object representing this plugin library as long as
214 // it is loaded.
215 class MyModule : public pp::Module {
216 public:
217 MyModule() : pp::Module() {}
218 virtual ~MyModule() {}
220 // Override CreateInstance to create your customized Instance object.
221 virtual pp::Instance* CreateInstance(PP_Instance instance) {
222 return new MyInstance(instance);
226 namespace pp {
228 // Factory function for your specialization of the Module object.
229 Module* CreateModule() {
230 return new MyModule();
233 } // namespace pp