1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
|
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif
#include <stdint.h>
#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_ = static_cast<int>(width_ * device_scale_);
pixel_height_ = static_cast<int>(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(
static_cast<int32_t>(position.x() * device_scale_),
static_cast<int32_t>(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(static_cast<int32_t>(position.x() / css_scale_),
static_cast<int32_t>(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 = static_cast<float>((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
|