Index: ppapi/examples/scaling/scaling.cc |
diff --git a/ppapi/examples/scaling/scaling.cc b/ppapi/examples/scaling/scaling.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..01d9265123eb43531b5884c312903f2c3184ee97 |
--- /dev/null |
+++ b/ppapi/examples/scaling/scaling.cc |
@@ -0,0 +1,232 @@ |
+// Copyright (c) 2013 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. |
+ |
+#include <sstream> |
+ |
+#include "ppapi/c/pp_errors.h" |
+#include "ppapi/cpp/completion_callback.h" |
+#include "ppapi/cpp/graphics_2d.h" |
+#include "ppapi/cpp/image_data.h" |
+#include "ppapi/cpp/input_event.h" |
+#include "ppapi/cpp/instance.h" |
+#include "ppapi/cpp/module.h" |
+#include "ppapi/cpp/rect.h" |
+#include "ppapi/cpp/var.h" |
+#include "ppapi/utility/completion_callback_factory.h" |
+ |
+// When compiling natively on Windows, PostMessage can be #define-d to |
+// something else. |
+#ifdef PostMessage |
+#undef PostMessage |
+#endif |
+ |
+// Example plugin to demonstrate usage of pp::View and pp::Graphics2D APIs for |
+// rendering 2D graphics at device resolution. See Paint() for more details. |
+class MyInstance : public pp::Instance { |
+ public: |
+ explicit MyInstance(PP_Instance instance) |
+ : pp::Instance(instance), |
+ width_(0), |
+ height_(0), |
+ pixel_width_(0), |
+ pixel_height_(0), |
+ device_scale_(1.0f), |
+ css_scale_(1.0f), |
+ using_device_pixels_(true) { |
+ RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | |
+ PP_INPUTEVENT_CLASS_KEYBOARD); |
+ } |
+ |
+ virtual void DidChangeView(const pp::View& view) { |
+ pp::Rect view_rect = view.GetRect(); |
+ if (view_rect.width() == width_ && |
+ view_rect.height() == height_ && |
+ view.GetDeviceScale() == device_scale_ && |
+ view.GetCSSScale() == css_scale_) |
+ return; // We don't care about the position, only the size and scale. |
+ |
+ width_ = view_rect.width(); |
+ height_ = view_rect.height(); |
+ device_scale_ = view.GetDeviceScale(); |
+ css_scale_ = view.GetCSSScale(); |
+ |
+ pixel_width_ = width_ * device_scale_; |
+ pixel_height_ = height_ * device_scale_; |
+ |
+ SetupGraphics(); |
+ } |
+ |
+ virtual bool HandleInputEvent(const pp::InputEvent& event) { |
+ switch (event.GetType()) { |
+ case PP_INPUTEVENT_TYPE_MOUSEDOWN: |
+ HandleMouseDown(event); |
+ return true; |
+ default: |
+ return false; |
+ } |
+ } |
+ |
+ virtual void HandleMessage(const pp::Var& message_data) { |
+ if (message_data.is_string()) { |
+ std::string str = message_data.AsString(); |
+ if (str == "dip") { |
+ if (using_device_pixels_) { |
+ using_device_pixels_ = false; |
+ SetupGraphics(); |
+ } |
+ } else if (str == "device") { |
+ if (!using_device_pixels_) { |
+ using_device_pixels_ = true; |
+ SetupGraphics(); |
+ } |
+ } else if (str == "metrics") { |
+ std::stringstream stream; |
+ stream << "DIP (" << width_ << ", " << height_ << "), device pixels=(" |
+ << pixel_width_ << ", " << pixel_height_ <<"), device_scale=" |
+ << device_scale_ <<", css_scale=" << css_scale_; |
+ PostMessage(stream.str()); |
+ } |
+ } |
+ } |
+ |
+ private: |
+ void HandleMouseDown(const pp::InputEvent& event) { |
+ pp::MouseInputEvent mouse_event(event); |
+ pp::Point position(mouse_event.GetPosition()); |
+ pp::Point position_device(position.x() * device_scale_, |
+ position.y() * device_scale_); |
+ std::stringstream stream; |
+ stream << "Mousedown at DIP (" << position.x() << ", " << position.y() |
+ << "), device pixel (" << position_device.x() << ", " |
+ << position_device.y() << ")"; |
+ if (css_scale_ > 0.0f) { |
+ pp::Point position_css(position.x() / css_scale_, |
+ position.y() / css_scale_); |
+ stream << ", CSS pixel (" << position_css.x() << ", " << position_css.y() |
+ <<")"; |
+ } else { |
+ stream <<", unknown CSS pixel. css_scale_=" << css_scale_; |
+ } |
+ PostMessage(stream.str()); |
+ } |
+ |
+ void SetupGraphics() { |
+ if (using_device_pixels_) { |
+ // The plugin will treat 1 pixel in the device context as 1 device pixel. |
+ // This will set up a properly-sized pp::Graphics2D, and tell Pepper |
+ // to apply the correct scale so the resulting concatenated scale leaves |
+ // each pixel in the device context as one on the display device. |
+ device_context_ = pp::Graphics2D(this, |
+ pp::Size(pixel_width_, pixel_height_), |
+ true); |
+ if (device_scale_ > 0.0f) { |
+ // If SetScale is promoted to pp::Graphics2D, the dc_dev constructor |
+ // can be removed, and this will become the following line instead. |
+ // device_context_.SetScale(1.0f / device_scale_); |
+ device_context_.SetScale(1.0f / device_scale_); |
+ } |
+ } else { |
+ // The plugin will treat 1 pixel in the device context as one DIP. |
+ device_context_ = pp::Graphics2D(this, pp::Size(width_, height_), true); |
+ } |
+ BindGraphics(device_context_); |
+ Paint(); |
+ } |
+ |
+ void Paint() { |
+ int width = using_device_pixels_ ? pixel_width_ : width_; |
+ int height = using_device_pixels_ ? pixel_height_ : height_; |
+ pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, |
+ pp::Size(width, height), false); |
+ if (image.is_null()) |
+ return; |
+ |
+ // Painting here will demonstrate a few techniques: |
+ // - painting a thin blue box and cross-hatch to show the finest resolution |
+ // available. |
+ // - painting a 25 DIP (logical pixel) green circle to show how objects of a |
+ // fixed size in DIPs should be scaled if using a high-resolution |
+ // pp::Graphics2D. |
+ // - paiting a 50 CSS pixel red circle to show how objects of a fixed size |
+ // in CSS pixels should be scaled if using a high-resolution |
+ // pp::Graphics2D, as well as how to use the GetCSSScale value properly. |
+ |
+ // Painting in "DIP resolution" mode (|using_device_pixels_| false) will |
+ // demonstrate how unscaled graphics would look, even on a high-DPI device. |
+ // Painting in "device resolution" mode (|using_device_pixels_| true) will |
+ // show how scaled graphics would look crisper on a high-DPI device, in |
+ // comparison to using unscaled graphics. Both modes should look identical |
+ // when displayed on a non-high-DPI device (window.devicePixelRatio == 1). |
+ // Toggling between "DIP resolution" mode and "device resolution" mode |
+ // should not change the sizes of the circles. |
+ |
+ // Changing the browser zoom level should cause the CSS circle to zoom, but |
+ // not the DIP-sized circle. |
+ |
+ // All painting here does not use any anti-aliasing. |
+ float circle_1_radius = 25; |
+ if (using_device_pixels_) |
+ circle_1_radius *= device_scale_; |
+ |
+ float circle_2_radius = 50 * css_scale_; |
+ if (using_device_pixels_) |
+ circle_2_radius *= device_scale_; |
+ |
+ for (int y = 0; y < height; ++y) { |
+ char* row = static_cast<char*>(image.data()) + (y * image.stride()); |
+ uint32_t* pixel = reinterpret_cast<uint32_t*>(row); |
+ for (int x = 0; x < width; ++x) { |
+ int dx = (width / 2) - x; |
+ int dy = (height / 2) - y; |
+ float dist_squared = (dx * dx) + (dy * dy); |
+ if (x == 0 || y == 0 || x == width - 1 || y == width - 1 || x == y || |
+ width - x - 1 == y) { |
+ *pixel++ = 0xFF0000FF; |
+ } else if (dist_squared < circle_1_radius * circle_1_radius) { |
+ *pixel++ = 0xFF00FF00; |
+ } else if (dist_squared < circle_2_radius * circle_2_radius) { |
+ *pixel++ = 0xFFFF0000; |
+ } else { |
+ *pixel++ = 0xFF000000; |
+ } |
+ } |
+ } |
+ |
+ device_context_.ReplaceContents(&image); |
+ device_context_.Flush(pp::CompletionCallback(&OnFlush, this)); |
+ } |
+ |
+ static void OnFlush(void* user_data, int32_t result) {} |
+ |
+ pp::Graphics2D device_context_; |
+ int width_; |
+ int height_; |
+ int pixel_width_; |
+ int pixel_height_; |
+ float device_scale_; |
+ float css_scale_; |
+ bool using_device_pixels_; |
+}; |
+ |
+// This object is the global object representing this plugin library as long as |
+// it is loaded. |
+class MyModule : public pp::Module { |
+ public: |
+ MyModule() : pp::Module() {} |
+ virtual ~MyModule() {} |
+ |
+ // Override CreateInstance to create your customized Instance object. |
+ virtual pp::Instance* CreateInstance(PP_Instance instance) { |
+ return new MyInstance(instance); |
+ } |
+}; |
+ |
+namespace pp { |
+ |
+// Factory function for your specialization of the Module object. |
+Module* CreateModule() { |
+ return new MyModule(); |
+} |
+ |
+} // namespace pp |