15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include <algorithm>
68bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/c/pp_input_event.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/graphics_2d.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/image_data.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/input_event.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/instance.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/module.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/size.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/view.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/utility/graphics/paint_manager.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Number of pixels to each side of the center of the square that we draw.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kSquareRadius = 2;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We identify our square by the center point. This computes the rect for the
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// square given that point.
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)pp::Rect SquareForPoint(int x, int y) {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return PP_MakeRectFromXYWH(x - kSquareRadius, y - kSquareRadius,
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             kSquareRadius * 2 + 1, kSquareRadius * 2 + 1);
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void FillRect(pp::ImageData* image,
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     int left, int top, int width, int height,
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     uint32_t color) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int y = std::max(0, top);
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       y < std::min(image->size().height() - 1, top + height);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       y++) {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int x = std::max(0, left);
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         x < std::min(image->size().width() - 1, left + width);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         x++)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *image->GetAddr32(pp::Point(x, y)) = color;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MyInstance : public pp::Instance, public pp::PaintManager::Client {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MyInstance(PP_Instance instance)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : pp::Instance(instance),
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        paint_manager_(),
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        last_x_(0),
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        last_y_(0) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paint_manager_.Initialize(this, this, false);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool HandleInputEvent(const pp::InputEvent& event) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (event.GetType()) {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PP_INPUTEVENT_TYPE_MOUSEDOWN: {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pp::MouseInputEvent mouse_event(event);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Update the square on a mouse down.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          UpdateSquare(static_cast<int>(mouse_event.GetPosition().x()),
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       static_cast<int>(mouse_event.GetPosition().y()));
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pp::MouseInputEvent mouse_event(event);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Update the square on a drag.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT) {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          UpdateSquare(static_cast<int>(mouse_event.GetPosition().x()),
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       static_cast<int>(mouse_event.GetPosition().y()));
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void DidChangeView(const pp::View& view) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paint_manager_.SetSize(view.GetRect().size());
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // PaintManager::Client implementation.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool OnPaint(pp::Graphics2D& graphics_2d,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const std::vector<pp::Rect>& paint_rects,
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const pp::Rect& paint_bounds) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make an image just large enough to hold all dirty rects. We won't
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // actually paint all of these pixels below, but rather just the dirty
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // ones. Since image allocation can be somewhat heavyweight, we wouldn't
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // want to allocate separate images in the case of multiple dirty rects.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pp::ImageData updated_image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                paint_bounds.size(), false);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We could repaint everything inside the image we made above. For this
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // example, that would probably be the easiest thing since updates are
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // small and typically close to each other. However, for the purposes of
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // demonstration, here we only actually paint the pixels that changed,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // which may be the entire update region, or could be multiple discontigous
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // regions inside the update region.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Note that the aggregator used by the paint manager won't give us
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // multiple regions that overlap, so we don't have to worry about double
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // painting in this code.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < paint_rects.size(); i++) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Since our image is just the invalid region, we need to offset the
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // areas we paint by that much. This is just a light blue background.
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FillRect(&updated_image,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               paint_rects[i].x() - paint_bounds.x(),
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               paint_rects[i].y() - paint_bounds.y(),
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               paint_rects[i].width(),
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               paint_rects[i].height(),
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               0xFFAAAAFF);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Paint the square black. Because we're lazy, we do this outside of the
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // loop above.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pp::Rect square = SquareForPoint(last_x_, last_y_);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FillRect(&updated_image,
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             square.x() - paint_bounds.x(),
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             square.y() - paint_bounds.y(),
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             square.width(),
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             square.height(),
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             0xFF000000);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    graphics_2d.PaintImageData(updated_image, paint_bounds.point());
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void UpdateSquare(int x, int y) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (x == last_x_ && y == last_y_)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;  // Nothing changed.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Invalidate the region around the old square which needs to be repainted
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // because it's no longer there.
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paint_manager_.InvalidateRect(SquareForPoint(last_x_, last_y_));
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the current position.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_x_ = x;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_y_ = y;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Also invalidate the region around the new square.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paint_manager_.InvalidateRect(SquareForPoint(last_x_, last_y_));
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::PaintManager paint_manager_;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int last_x_;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int last_y_;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MyModule : public pp::Module {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual pp::Instance* CreateInstance(PP_Instance instance) {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return new MyInstance(instance);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace pp {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Factory function for your specialization of the Module object.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Module* CreateModule() {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new MyModule();
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace pp
164