Home | History | Annotate | Download | only in input
      1 // Copyright (c) 2012 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 "ppapi/c/pp_input_event.h"
      6 #include "ppapi/cpp/graphics_2d.h"
      7 #include "ppapi/cpp/image_data.h"
      8 #include "ppapi/cpp/input_event.h"
      9 #include "ppapi/cpp/instance.h"
     10 #include "ppapi/cpp/module.h"
     11 #include "ppapi/cpp/size.h"
     12 #include "ppapi/cpp/view.h"
     13 #include "ppapi/utility/graphics/paint_manager.h"
     14 
     15 // Number of pixels to each side of the center of the square that we draw.
     16 static const int kSquareRadius = 2;
     17 
     18 // We identify our square by the center point. This computes the rect for the
     19 // square given that point.
     20 pp::Rect SquareForPoint(int x, int y) {
     21   return PP_MakeRectFromXYWH(x - kSquareRadius, y - kSquareRadius,
     22                              kSquareRadius * 2 + 1, kSquareRadius * 2 + 1);
     23 }
     24 
     25 static void FillRect(pp::ImageData* image,
     26                      int left, int top, int width, int height,
     27                      uint32_t color) {
     28   for (int y = std::max(0, top);
     29        y < std::min(image->size().height() - 1, top + height);
     30        y++) {
     31     for (int x = std::max(0, left);
     32          x < std::min(image->size().width() - 1, left + width);
     33          x++)
     34       *image->GetAddr32(pp::Point(x, y)) = color;
     35   }
     36 }
     37 
     38 class MyInstance : public pp::Instance, public pp::PaintManager::Client {
     39  public:
     40   MyInstance(PP_Instance instance)
     41       : pp::Instance(instance),
     42         paint_manager_(),
     43         last_x_(0),
     44         last_y_(0) {
     45     paint_manager_.Initialize(this, this, false);
     46     RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_TOUCH);
     47   }
     48 
     49   virtual bool HandleInputEvent(const pp::InputEvent& event) {
     50     switch (event.GetType()) {
     51       case PP_INPUTEVENT_TYPE_MOUSEDOWN: {
     52         pp::MouseInputEvent mouse_event(event);
     53         // Update the square on a mouse down.
     54         if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT) {
     55           UpdateSquare(static_cast<int>(mouse_event.GetPosition().x()),
     56                        static_cast<int>(mouse_event.GetPosition().y()));
     57         }
     58         return true;
     59       }
     60       case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
     61         pp::MouseInputEvent mouse_event(event);
     62         // Update the square on a drag.
     63         if (mouse_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT) {
     64           UpdateSquare(static_cast<int>(mouse_event.GetPosition().x()),
     65                        static_cast<int>(mouse_event.GetPosition().y()));
     66         }
     67         return true;
     68       }
     69 
     70       case PP_INPUTEVENT_TYPE_TOUCHSTART: {
     71         pp::TouchInputEvent touch(event);
     72         // Update the square on a touch down.
     73         uint32_t count = touch.GetTouchCount(PP_TOUCHLIST_TYPE_CHANGEDTOUCHES);
     74         for (uint32_t i = 0; i < count; ++i) {
     75           pp::TouchPoint point = touch.GetTouchByIndex(
     76               PP_TOUCHLIST_TYPE_CHANGEDTOUCHES, i);
     77           UpdateSquare(static_cast<int>(point.position().x()),
     78                        static_cast<int>(point.position().y()));
     79         }
     80         return true;
     81       }
     82       case PP_INPUTEVENT_TYPE_TOUCHMOVE:
     83       case PP_INPUTEVENT_TYPE_TOUCHEND:
     84       case PP_INPUTEVENT_TYPE_TOUCHCANCEL:
     85         return true;
     86 
     87       default:
     88         return false;
     89     }
     90   }
     91 
     92   virtual void DidChangeView(const pp::View& view) {
     93     paint_manager_.SetSize(view.GetRect().size());
     94   }
     95 
     96   // PaintManager::Client implementation.
     97   virtual bool OnPaint(pp::Graphics2D& graphics_2d,
     98                        const std::vector<pp::Rect>& paint_rects,
     99                        const pp::Rect& paint_bounds) {
    100     // Make an image just large enough to hold all dirty rects. We won't
    101     // actually paint all of these pixels below, but rather just the dirty
    102     // ones. Since image allocation can be somewhat heavyweight, we wouldn't
    103     // want to allocate separate images in the case of multiple dirty rects.
    104     pp::ImageData updated_image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
    105                                 paint_bounds.size(), false);
    106 
    107     // We could repaint everything inside the image we made above. For this
    108     // example, that would probably be the easiest thing since updates are
    109     // small and typically close to each other. However, for the purposes of
    110     // demonstration, here we only actually paint the pixels that changed,
    111     // which may be the entire update region, or could be multiple discontigous
    112     // regions inside the update region.
    113     //
    114     // Note that the aggregator used by the paint manager won't give us
    115     // multiple regions that overlap, so we don't have to worry about double
    116     // painting in this code.
    117     for (size_t i = 0; i < paint_rects.size(); i++) {
    118       // Since our image is just the invalid region, we need to offset the
    119       // areas we paint by that much. This is just a light blue background.
    120       FillRect(&updated_image,
    121                paint_rects[i].x() - paint_bounds.x(),
    122                paint_rects[i].y() - paint_bounds.y(),
    123                paint_rects[i].width(),
    124                paint_rects[i].height(),
    125                0xFFAAAAFF);
    126     }
    127 
    128     // Paint the square black. Because we're lazy, we do this outside of the
    129     // loop above.
    130     pp::Rect square = SquareForPoint(last_x_, last_y_);
    131     FillRect(&updated_image,
    132              square.x() - paint_bounds.x(),
    133              square.y() - paint_bounds.y(),
    134              square.width(),
    135              square.height(),
    136              0xFF000000);
    137 
    138     graphics_2d.PaintImageData(updated_image, paint_bounds.point());
    139     return true;
    140   }
    141 
    142  private:
    143   void UpdateSquare(int x, int y) {
    144     if (x == last_x_ && y == last_y_)
    145       return;  // Nothing changed.
    146 
    147     // Invalidate the region around the old square which needs to be repainted
    148     // because it's no longer there.
    149     paint_manager_.InvalidateRect(SquareForPoint(last_x_, last_y_));
    150 
    151     // Update the current position.
    152     last_x_ = x;
    153     last_y_ = y;
    154 
    155     // Also invalidate the region around the new square.
    156     paint_manager_.InvalidateRect(SquareForPoint(last_x_, last_y_));
    157   }
    158 
    159   pp::PaintManager paint_manager_;
    160 
    161   int last_x_;
    162   int last_y_;
    163 };
    164 
    165 class MyModule : public pp::Module {
    166  public:
    167   virtual pp::Instance* CreateInstance(PP_Instance instance) {
    168     return new MyInstance(instance);
    169   }
    170 };
    171 
    172 namespace pp {
    173 
    174 // Factory function for your specialization of the Module object.
    175 Module* CreateModule() {
    176   return new MyModule();
    177 }
    178 
    179 }  // namespace pp
    180