OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include <sstream> |
| 6 |
| 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" |
| 17 |
| 18 // When compiling natively on Windows, PostMessage can be #define-d to |
| 19 // something else. |
| 20 #ifdef PostMessage |
| 21 #undef PostMessage |
| 22 #endif |
| 23 |
| 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); |
| 39 } |
| 40 |
| 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. |
| 48 |
| 49 width_ = view_rect.width(); |
| 50 height_ = view_rect.height(); |
| 51 device_scale_ = view.GetDeviceScale(); |
| 52 css_scale_ = view.GetCSSScale(); |
| 53 |
| 54 pixel_width_ = width_ * device_scale_; |
| 55 pixel_height_ = height_ * device_scale_; |
| 56 |
| 57 SetupGraphics(); |
| 58 } |
| 59 |
| 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; |
| 67 } |
| 68 } |
| 69 |
| 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(); |
| 77 } |
| 78 } else if (str == "device") { |
| 79 if (!using_device_pixels_) { |
| 80 using_device_pixels_ = true; |
| 81 SetupGraphics(); |
| 82 } |
| 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()); |
| 89 } |
| 90 } |
| 91 } |
| 92 |
| 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(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() |
| 107 <<")"; |
| 108 } else { |
| 109 stream <<", unknown CSS pixel. css_scale_=" << css_scale_; |
| 110 } |
| 111 PostMessage(stream.str()); |
| 112 } |
| 113 |
| 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_), |
| 122 true); |
| 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_); |
| 128 } |
| 129 } else { |
| 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); |
| 132 } |
| 133 BindGraphics(device_context_); |
| 134 Paint(); |
| 135 } |
| 136 |
| 137 void Paint() { |
| 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); |
| 142 if (image.is_null()) |
| 143 return; |
| 144 |
| 145 // Painting here will demonstrate a few techniques: |
| 146 // - painting a thin blue box and cross-hatch to show the finest resolution |
| 147 // available. |
| 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 |
| 150 // pp::Graphics2D. |
| 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. |
| 154 |
| 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. |
| 163 |
| 164 // Changing the browser zoom level should cause the CSS circle to zoom, but |
| 165 // not the DIP-sized circle. |
| 166 |
| 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_; |
| 171 |
| 172 float circle_2_radius = 50 * css_scale_; |
| 173 if (using_device_pixels_) |
| 174 circle_2_radius *= device_scale_; |
| 175 |
| 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; |
| 190 } else { |
| 191 *pixel++ = 0xFF000000; |
| 192 } |
| 193 } |
| 194 } |
| 195 |
| 196 device_context_.ReplaceContents(&image); |
| 197 device_context_.Flush(pp::CompletionCallback(&OnFlush, this)); |
| 198 } |
| 199 |
| 200 static void OnFlush(void* user_data, int32_t result) {} |
| 201 |
| 202 pp::Graphics2D device_context_; |
| 203 int width_; |
| 204 int height_; |
| 205 int pixel_width_; |
| 206 int pixel_height_; |
| 207 float device_scale_; |
| 208 float css_scale_; |
| 209 bool using_device_pixels_; |
| 210 }; |
| 211 |
| 212 // This object is the global object representing this plugin library as long as |
| 213 // it is loaded. |
| 214 class MyModule : public pp::Module { |
| 215 public: |
| 216 MyModule() : pp::Module() {} |
| 217 virtual ~MyModule() {} |
| 218 |
| 219 // Override CreateInstance to create your customized Instance object. |
| 220 virtual pp::Instance* CreateInstance(PP_Instance instance) { |
| 221 return new MyInstance(instance); |
| 222 } |
| 223 }; |
| 224 |
| 225 namespace pp { |
| 226 |
| 227 // Factory function for your specialization of the Module object. |
| 228 Module* CreateModule() { |
| 229 return new MyModule(); |
| 230 } |
| 231 |
| 232 } // namespace pp |
OLD | NEW |