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
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include "ppapi/c/pp_input_event.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/size.h"
#include "ppapi/cpp/view.h"
#include "ppapi/utility/graphics/paint_manager.h"
// Number of pixels to each side of the center of the square that we draw.
static const int kSquareRadius = 2;
// We identify our square by the center point. This computes the rect for the
// square given that point.
pp::Rect SquareForPoint(int x, int y) {
return PP_MakeRectFromXYWH(x - kSquareRadius, y - kSquareRadius,
kSquareRadius * 2 + 1, kSquareRadius * 2 + 1);
}
static void FillRect(pp::ImageData* image,
int left, int top, int width, int height,
uint32_t color) {
for (int y = std::max(0, top);
y < std::min(image->size().height() - 1, top + height);
y++) {
for (int x = std::max(0, left);
x < std::min(image->size().width() - 1, left + width);
x++)
*image->GetAddr32(pp::Point(x, y)) = color;
}
}
class MyInstance : public pp::Instance, public pp::PaintManager::Client {
public:
MyInstance(PP_Instance instance)
: pp::Instance(instance),
paint_manager_(),
last_x_(0),
last_y_(0) {
paint_manager_.Initialize(this, this, false);
RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_TOUCH);
}
virtual bool HandleInputEvent(const pp::InputEvent& event) {
switch (event.GetType()) {
case PP_INPUTEVENT_TYPE_MOUSEDOWN: {
pp::MouseInputEvent mouse_event(event);
// Update the square on a mouse down.
if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT) {
UpdateSquare(static_cast<int>(mouse_event.GetPosition().x()),
static_cast<int>(mouse_event.GetPosition().y()));
}
return true;
}
case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
pp::MouseInputEvent mouse_event(event);
// Update the square on a drag.
if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT) {
UpdateSquare(static_cast<int>(mouse_event.GetPosition().x()),
static_cast<int>(mouse_event.GetPosition().y()));
}
return true;
}
case PP_INPUTEVENT_TYPE_TOUCHSTART: {
pp::TouchInputEvent touch(event);
// Update the square on a touch down.
uint32_t count = touch.GetTouchCount(PP_TOUCHLIST_TYPE_CHANGEDTOUCHES);
for (uint32_t i = 0; i < count; ++i) {
pp::TouchPoint point = touch.GetTouchByIndex(
PP_TOUCHLIST_TYPE_CHANGEDTOUCHES, i);
UpdateSquare(static_cast<int>(point.position().x()),
static_cast<int>(point.position().y()));
}
return true;
}
case PP_INPUTEVENT_TYPE_TOUCHMOVE:
case PP_INPUTEVENT_TYPE_TOUCHEND:
case PP_INPUTEVENT_TYPE_TOUCHCANCEL:
return true;
default:
return false;
}
}
virtual void DidChangeView(const pp::View& view) {
paint_manager_.SetSize(view.GetRect().size());
}
// PaintManager::Client implementation.
virtual bool OnPaint(pp::Graphics2D& graphics_2d,
const std::vector<pp::Rect>& paint_rects,
const pp::Rect& paint_bounds) {
// Make an image just large enough to hold all dirty rects. We won't
// actually paint all of these pixels below, but rather just the dirty
// ones. Since image allocation can be somewhat heavyweight, we wouldn't
// want to allocate separate images in the case of multiple dirty rects.
pp::ImageData updated_image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
paint_bounds.size(), false);
// We could repaint everything inside the image we made above. For this
// example, that would probably be the easiest thing since updates are
// small and typically close to each other. However, for the purposes of
// demonstration, here we only actually paint the pixels that changed,
// which may be the entire update region, or could be multiple discontigous
// regions inside the update region.
//
// Note that the aggregator used by the paint manager won't give us
// multiple regions that overlap, so we don't have to worry about double
// painting in this code.
for (size_t i = 0; i < paint_rects.size(); i++) {
// Since our image is just the invalid region, we need to offset the
// areas we paint by that much. This is just a light blue background.
FillRect(&updated_image,
paint_rects[i].x() - paint_bounds.x(),
paint_rects[i].y() - paint_bounds.y(),
paint_rects[i].width(),
paint_rects[i].height(),
0xFFAAAAFF);
}
// Paint the square black. Because we're lazy, we do this outside of the
// loop above.
pp::Rect square = SquareForPoint(last_x_, last_y_);
FillRect(&updated_image,
square.x() - paint_bounds.x(),
square.y() - paint_bounds.y(),
square.width(),
square.height(),
0xFF000000);
graphics_2d.PaintImageData(updated_image, paint_bounds.point());
return true;
}
private:
void UpdateSquare(int x, int y) {
if (x == last_x_ && y == last_y_)
return; // Nothing changed.
// Invalidate the region around the old square which needs to be repainted
// because it's no longer there.
paint_manager_.InvalidateRect(SquareForPoint(last_x_, last_y_));
// Update the current position.
last_x_ = x;
last_y_ = y;
// Also invalidate the region around the new square.
paint_manager_.InvalidateRect(SquareForPoint(last_x_, last_y_));
}
pp::PaintManager paint_manager_;
int last_x_;
int last_y_;
};
class MyModule : public pp::Module {
public:
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
|