Add a 'fatbits' mode to unix sample app.


git-svn-id: http://skia.googlecode.com/svn/trunk@978 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/views/SkOSWindow_Unix.h b/include/views/SkOSWindow_Unix.h
index e991828..4e8db55 100644
--- a/include/views/SkOSWindow_Unix.h
+++ b/include/views/SkOSWindow_Unix.h
@@ -22,6 +22,7 @@
 
 class SkBitmap;
 class SkEvent;
+class SkTypeface;
 
 struct SkUnixWindow {
   Display* fDisplay;
@@ -42,6 +43,10 @@
     bool attachGL();
     void detachGL();
     void presentGL();
+    void updatePointer(int x, int y);
+    void toggleZoomer();
+    bool zoomIn();
+    bool zoomOut();
 
     //static bool PostEvent(SkEvent* evt, SkEventSinkID, SkMSec delay);
 
@@ -60,6 +65,12 @@
     SkUnixWindow  fUnixWindow;
 
     void    doPaint();
+    // Latest position of the mouse.
+    int fMouseX, fMouseY;
+    int fScale;
+    // Used by the text showing position and color values.
+    SkTypeface* fTypeface;
+    bool fShowZoomer;
 
     typedef SkWindow INHERITED;
 };
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index bb55da3..b7fe051 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -825,6 +825,18 @@
             this->updateTitle();
             this->inval(NULL);
             break;
+#ifdef SK_BUILD_FOR_UNIX
+        // These methods have not been written for other platforms yet.
+        case 'i':
+            this->zoomIn();
+            break;
+        case 'o':
+            this->zoomOut();
+            break;
+        case 'z':
+            this->toggleZoomer();
+            break;
+#endif
         default:
             break;
     }
diff --git a/src/utils/unix/SkOSWindow_Unix.cpp b/src/utils/unix/SkOSWindow_Unix.cpp
index 650ced2..8e348ac 100644
--- a/src/utils/unix/SkOSWindow_Unix.cpp
+++ b/src/utils/unix/SkOSWindow_Unix.cpp
@@ -6,16 +6,23 @@
 #include "SkWindow.h"
 
 #include "SkBitmap.h"
+#include "SkCanvas.h"
 #include "SkColor.h"
 #include "SkEvent.h"
+#include "SkTypeface.h"
 
 SkOSWindow::SkOSWindow(void* unused)
 {
     fUnixWindow.fDisplay = NULL;
+    fMouseX = fMouseY = 0;
+    fTypeface = SkTypeface::CreateFromTypeface(NULL, SkTypeface::kBold);
+    fShowZoomer = false;
+    fScale = 4;
 }
 
 SkOSWindow::~SkOSWindow()
 {
+    fTypeface->unref();
 }
 
 void SkOSWindow::setUnixWindow(Display* dsp, Window win, size_t screenNumber, GC gc)
@@ -41,6 +48,29 @@
 
 }
 
+bool SkOSWindow::zoomIn()
+{
+    // Arbitrarily decided
+    if (fScale == 25) return false;
+    fScale++;
+    inval(NULL);
+    return true;
+}
+
+bool SkOSWindow::zoomOut()
+{
+    if (fScale == 1) return false;
+    fScale--;
+    inval(NULL);
+    return true;
+}
+
+void SkOSWindow::toggleZoomer()
+{
+    fShowZoomer = !fShowZoomer;
+    inval(NULL);
+}
+
 void SkOSWindow::onSetTitle(const char title[])
 {
     if (!fUnixWindow.fDisplay) return;
@@ -68,12 +98,8 @@
     return INHERITED::onEvent(evt);
 }
 
-void SkOSWindow::doPaint() {
-    if (!fUnixWindow.fDisplay) return;
-    // Draw the bitmap to the screen.
-    const SkBitmap& bitmap = getBitmap();
-
-    XImage image;
+static bool convertBitmapToXImage(XImage& image, const SkBitmap& bitmap)
+{
     sk_bzero(&image, sizeof(image));
 
     int bitsPerPixel = bitmap.bytesPerPixel() * 8;
@@ -88,8 +114,131 @@
     image.depth = 24;
     image.bytes_per_line = bitmap.rowBytes() - bitmap.width() * bitmap.bytesPerPixel();
     image.bits_per_pixel = bitsPerPixel;
-    int status = XInitImage(&image);
-    XPutImage(fUnixWindow.fDisplay, fUnixWindow.fWin, fUnixWindow.fGc, &image, 0, 0, 0, 0, width(), height());
+    return XInitImage(&image);
+}
+
+void SkOSWindow::updatePointer(int x, int y)
+{
+    fMouseX = x;
+    fMouseY = y;
+    inval(NULL);
+}
+
+static void drawText(SkCanvas& canvas, SkString string, SkScalar left, SkScalar top, SkPaint& paint)
+{
+    SkColor desiredColor = paint.getColor();
+    paint.setColor(SK_ColorWHITE);
+    const char* c_str = string.c_str();
+    size_t size = string.size();
+    SkRect bounds;
+    paint.measureText(c_str, size, &bounds);
+    bounds.offset(left, top);
+    SkScalar inset = SkIntToScalar(-2);
+    bounds.inset(inset, inset);
+    canvas.drawRect(bounds, paint);
+    if (desiredColor != SK_ColorBLACK) {
+        paint.setColor(SK_ColorBLACK);
+        canvas.drawText(c_str, size, left + SK_Scalar1, top + SK_Scalar1, paint);
+    }
+    paint.setColor(desiredColor);
+    canvas.drawText(c_str, size, left, top, paint);
+}
+
+void SkOSWindow::doPaint() {
+    if (!fUnixWindow.fDisplay) return;
+    // Draw the bitmap to the screen.
+    const SkBitmap& bitmap = getBitmap();
+    int width = bitmap.width();
+    int height = bitmap.height();
+
+    if (!fShowZoomer) {
+        XImage image;
+        if (!convertBitmapToXImage(image, bitmap)) return;
+
+        XPutImage(fUnixWindow.fDisplay, fUnixWindow.fWin, fUnixWindow.fGc, &image, 0, 0, 0, 0, width, height);
+    } else {
+        // Ensure the mouse position is on screen.
+        if (fMouseX >= width) fMouseX = width - 1;
+        else if (fMouseX < 0) fMouseX = 0;
+        if (fMouseY >= height) fMouseY = height - 1;
+        else if (fMouseY < 0) fMouseY = 0;
+        // zoomedBitmap will show the original bitmap, plus a zoomed in view (fat bits).
+        SkBitmap zoomedBitmap;
+        bitmap.copyTo(&zoomedBitmap, bitmap.getConfig());
+        SkCanvas canvas(zoomedBitmap);
+        // Find the size of the zoomed in view, forced to be odd, so the examined pixel is in the middle.
+        int zoomedWidth = (width >> 2) | 1;
+        int zoomedHeight = (height >> 2) | 1;
+        SkIRect src;
+        src.set(0, 0, zoomedWidth / fScale, zoomedHeight / fScale);
+        src.offset(fMouseX - (src.width()>>1), fMouseY - (src.height()>>1));
+        SkRect dest;
+        dest.set(0, 0, SkIntToScalar(zoomedWidth), SkIntToScalar(zoomedHeight));
+        dest.offset(SkIntToScalar(width - zoomedWidth), SkIntToScalar(height - zoomedHeight));
+        SkPaint paint;
+        // Clear the background behind our zoomed in view
+        paint.setColor(SK_ColorWHITE);
+        canvas.drawRect(dest, paint);
+        canvas.drawBitmapRect(bitmap, &src, dest);
+        paint.setColor(SK_ColorBLACK);
+        paint.setStyle(SkPaint::kStroke_Style);
+        // Draw a border around the pixel in the middle
+        SkRect originalPixel;
+        originalPixel.set(SkIntToScalar(fMouseX), SkIntToScalar(fMouseY), SkIntToScalar(fMouseX + 1), SkIntToScalar(fMouseY + 1));
+        SkMatrix matrix;
+        SkRect scalarSrc;
+        scalarSrc.set(src);
+        SkColor color = bitmap.getColor(fMouseX, fMouseY);
+        if (matrix.setRectToRect(scalarSrc, dest, SkMatrix::kFill_ScaleToFit)) {
+            SkRect pixel;
+            matrix.mapRect(&pixel, originalPixel);
+            // TODO Perhaps measure the values and make the outline white if it's "dark"
+            if (color == SK_ColorBLACK) {
+                paint.setColor(SK_ColorWHITE);
+            }
+            canvas.drawRect(pixel, paint);
+        }
+        paint.setColor(SK_ColorBLACK);
+        // Draw a border around the destination rectangle
+        canvas.drawRect(dest, paint);
+        paint.setStyle(SkPaint::kStrokeAndFill_Style);
+        // Identify the pixel and its color on screen
+        paint.setTypeface(fTypeface);
+        paint.setAntiAlias(true);
+        SkScalar lineHeight = paint.getFontMetrics(NULL);
+        SkString string;
+        string.appendf("(%i, %i)", fMouseX, fMouseY);
+        SkScalar left = dest.fLeft + SkIntToScalar(3); 
+        SkScalar i = SK_Scalar1;
+        drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
+        // Alpha
+        i += SK_Scalar1;
+        string.reset();
+        string.appendf("A: %X", SkColorGetA(color));
+        drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
+        // Red
+        i += SK_Scalar1;
+        string.reset();
+        string.appendf("R: %X", SkColorGetR(color));
+        paint.setColor(SK_ColorRED);
+        drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
+        // Green
+        i += SK_Scalar1;
+        string.reset();
+        string.appendf("G: %X", SkColorGetG(color));
+        paint.setColor(SK_ColorGREEN);
+        drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
+        // Blue
+        i += SK_Scalar1;
+        string.reset();
+        string.appendf("B: %X", SkColorGetB(color));
+        paint.setColor(SK_ColorBLUE);
+        drawText(canvas, string, left, SkScalarMulAdd(lineHeight, i, dest.fTop), paint);
+        // Finally, put our bitmap on the screen
+        XImage zoomedImage;
+        convertBitmapToXImage(zoomedImage, zoomedBitmap);
+        XPutImage(fUnixWindow.fDisplay, fUnixWindow.fWin, fUnixWindow.fGc, &zoomedImage, 0, 0, 0, 0, width, height);
+    }
 }
 
 bool SkOSWindow::onHandleChar(SkUnichar)
diff --git a/unix_test_app/main.cpp b/unix_test_app/main.cpp
index dace89e..deb95bc 100644
--- a/unix_test_app/main.cpp
+++ b/unix_test_app/main.cpp
@@ -73,7 +73,7 @@
 
     // Determine which events to listen for.
     eventMask = StructureNotifyMask|ButtonPressMask|ButtonReleaseMask
-            |ExposureMask|Button1MotionMask|KeyPressMask|KeyReleaseMask;
+            |ExposureMask|PointerMotionMask|KeyPressMask|KeyReleaseMask;
     XSelectInput(dsp, win, eventMask);
  
     bool loop = true;
@@ -96,9 +96,10 @@
                     window->handleClick(evt.xbutton.x, evt.xbutton.y, SkView::Click::kUp_State);
                 break;
             case MotionNotify:
-                // Since we are only masking to get the motion events for when Button1 is pressed,
-                // we can assume the pointer is moving with Button1 pressed.
-                window->handleClick(evt.xmotion.x, evt.xmotion.y, SkView::Click::kMoved_State);
+                // FIXME: 272 corresponds to the left mouse button, but should be a constant.
+                if (evt.xmotion.state == 272)
+                    window->handleClick(evt.xmotion.x, evt.xmotion.y, SkView::Click::kMoved_State);
+                window->updatePointer(evt.xmotion.x, evt.xmotion.y);
                 break;
             case KeyPress:
             {