From 6e9d0ce099bde00d35abc8a8deef0ad728efda7e Mon Sep 17 00:00:00 2001
From: "jeremy@chromium.org"
 <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Mon, 29 Sep 2008 23:40:02 +0000
Subject: Sync Mac canvas implementation with Windows version, still a work in
 progress, not all unit tests pass yet.

Review URL: http://codereview.chromium.org/4339

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2702 0039d316-1c4b-4281-b951-d872f2087c98
---
 base/gfx/bitmap_platform_device_mac.cc | 62 +++++++++++++----------------
 base/gfx/bitmap_platform_device_mac.h  |  7 +---
 base/gfx/platform_canvas_mac.cc        | 73 +---------------------------------
 base/gfx/platform_canvas_mac.h         | 19 +--------
 base/gfx/platform_device_mac.cc        | 67 ++++++++++++++++++++++++++++++-
 base/gfx/platform_device_mac.h         | 12 +++---
 6 files changed, 102 insertions(+), 138 deletions(-)

(limited to 'base')

diff --git a/base/gfx/bitmap_platform_device_mac.cc b/base/gfx/bitmap_platform_device_mac.cc
index 0bae190..40b58cf 100755
--- a/base/gfx/bitmap_platform_device_mac.cc
+++ b/base/gfx/bitmap_platform_device_mac.cc
@@ -52,6 +52,7 @@ class BitmapPlatformDeviceMac::BitmapPlatformDeviceMacData
 
   // Create/destroy CoreGraphics context for our bitmap data.
   CGContextRef GetBitmapContext() {
+    LoadConfig();
     return bitmap_context_;
   }
 
@@ -64,8 +65,7 @@ class BitmapPlatformDeviceMac::BitmapPlatformDeviceMacData
   // Sets the transform and clip operations. This will not update the CGContext,
   // but will mark the config as dirty. The next call of LoadConfig will
   // pick up these changes.
-  void SetTransform(const SkMatrix& t);
-  void SetClipRegion(const SkRegion& region);
+  void SetMatrixClip(const SkMatrix& transform, const SkRegion& region);
 
   // Loads the current transform and clip into the DC. Can be called even when
   // |bitmap_context_| is NULL (will be a NOP).
@@ -109,19 +109,15 @@ BitmapPlatformDeviceMac::\
   rect.set(0, 0,
            CGBitmapContextGetWidth(bitmap_context_),
            CGBitmapContextGetHeight(bitmap_context_));
-  SkRegion region(rect);
-  SetClipRegion(region);
+  clip_region_ = SkRegion(rect);
+  transform_.reset();
   CGContextRetain(bitmap_context_);
 }
 
-void BitmapPlatformDeviceMac::BitmapPlatformDeviceMacData::SetTransform(
-    const SkMatrix& t) {
-  transform_ = t;
-  config_dirty_ = true;
-}
-
-void BitmapPlatformDeviceMac::BitmapPlatformDeviceMacData::SetClipRegion(
+void BitmapPlatformDeviceMac::BitmapPlatformDeviceMacData::SetMatrixClip(
+    const SkMatrix& transform,
     const SkRegion& region) {
+  transform_ = transform;
   clip_region_ = region;
   config_dirty_ = true;
 }
@@ -134,11 +130,10 @@ void BitmapPlatformDeviceMac::BitmapPlatformDeviceMacData::LoadConfig() {
   // Transform.
   SkMatrix t(transform_);
   LoadTransformToCGContext(bitmap_context_, t);
-
-  // TODO(brettw) we should support more than just rect clipping here.
-  SkIRect rect = clip_region_.getBounds();
-
-  CGContextClipToRect(bitmap_context_, SkIRectToCGRect(rect));
+  
+  t.setTranslateX(-t.getTranslateX());
+  t.setTranslateY(-t.getTranslateY());
+  LoadClippingRegionToCGContext(bitmap_context_, clip_region_, t);
 }
 
 
@@ -150,6 +145,8 @@ BitmapPlatformDeviceMac* BitmapPlatformDeviceMac::Create(CGContextRef context,
                                                          int width,
                                                          int height,
                                                          bool is_opaque) {
+  // TODO(playmobil): remove debug code.
+  //printf("BitmapPlatformDeviceMac::Create(%d,%d)\n", width, height);
   // each pixel is 4 bytes (RGBA):
   void* data = malloc(height * width * 4);
   if (!data) return NULL;
@@ -214,12 +211,9 @@ CGContextRef BitmapPlatformDeviceMac::GetBitmapContext() {
   return data_->GetBitmapContext();
 }
 
-void BitmapPlatformDeviceMac::SetTransform(const SkMatrix& matrix) {
-  data_->SetTransform(matrix);
-}
-
-void BitmapPlatformDeviceMac::SetClipRegion(const SkRegion& region) {
-  data_->SetClipRegion(region);
+void BitmapPlatformDeviceMac::setMatrixClip(const SkMatrix& transform, 
+                                            const SkRegion& region) {
+  data_->SetMatrixClip(transform, region);
 }
 
 void BitmapPlatformDeviceMac::DrawToContext(CGContextRef context, int x, int y,
@@ -253,6 +247,18 @@ void BitmapPlatformDeviceMac::DrawToContext(CGContextRef context, int x, int y,
   if (created_dc)
     data_->ReleaseBitmapContext();
 }
+  
+// Returns the color value at the specified location.
+SkColor BitmapPlatformDeviceMac::getColorAt(int x, int y) {
+  const SkBitmap& bitmap = accessBitmap(true);
+  SkAutoLockPixels lock(bitmap);
+  uint32_t* data = bitmap.getAddr32(0, 0);
+  return static_cast<SkColor>(data[x + y * width()]);
+}
+
+void BitmapPlatformDeviceMac::onAccessBitmap(SkBitmap*) {
+  // Not needed in CoreGraphics
+}
 
 void BitmapPlatformDeviceMac::processPixels(int x, int y,
                                             int width, int height, 
@@ -276,17 +282,5 @@ void BitmapPlatformDeviceMac::processPixels(int x, int y,
   }
 }
 
-// Returns the color value at the specified location.
-SkColor BitmapPlatformDeviceMac::GetColorAt(int x, int y) {
-  const SkBitmap& bitmap = accessBitmap(true);
-  SkAutoLockPixels lock(bitmap);
-  uint32_t* data = bitmap.getAddr32(0, 0);
-  return static_cast<SkColor>(data[x + y * width()]);
-}
-
-void BitmapPlatformDeviceMac::onAccessBitmap(SkBitmap*) {
-  // Not needed in CoreGraphics
-}
-
 }  // namespace gfx
 
diff --git a/base/gfx/bitmap_platform_device_mac.h b/base/gfx/bitmap_platform_device_mac.h
index fdbe2e4..a008444 100755
--- a/base/gfx/bitmap_platform_device_mac.h
+++ b/base/gfx/bitmap_platform_device_mac.h
@@ -56,10 +56,7 @@ class BitmapPlatformDeviceMac : public PlatformDeviceMac {
   BitmapPlatformDeviceMac& operator=(const BitmapPlatformDeviceMac& other);
 
   virtual CGContextRef GetBitmapContext();
-  virtual void SetTransform(const SkMatrix& matrix);
-
-  // This currently only supports extremely simple clip rects.
-  virtual void SetClipRegion(const SkRegion& region);
+  virtual void setMatrixClip(const SkMatrix& transform, const SkRegion& region);
 
   virtual void DrawToContext(CGContextRef context, int x, int y,
                              const CGRect* src_rect);
@@ -68,7 +65,7 @@ class BitmapPlatformDeviceMac : public PlatformDeviceMac {
   
   // Returns the color value at the specified location. This does not
   // consider any transforms that may be set on the device.
-  SkColor GetColorAt(int x, int y);
+  SkColor getColorAt(int x, int y);
 
  protected:
   // Reference counted data that can be shared between multiple devices. This
diff --git a/base/gfx/platform_canvas_mac.cc b/base/gfx/platform_canvas_mac.cc
index ef06e0e..102655c 100755
--- a/base/gfx/platform_canvas_mac.cc
+++ b/base/gfx/platform_canvas_mac.cc
@@ -52,81 +52,10 @@ PlatformDeviceMac& PlatformCanvasMac::getTopPlatformDevice() const {
   return *static_cast<PlatformDeviceMac*>(iter.device());
 }
 
-// Clipping -------------------------------------------------------------------
-
-bool PlatformCanvasMac::clipRect(const SkRect& rect, SkRegion::Op op) {
-  bool ret = SkCanvas::clipRect(rect, op);
-  getTopPlatformDevice().SetClipRegion(getTotalClip());
-  return ret;
-}
-
-bool PlatformCanvasMac::clipPath(const SkPath& path, SkRegion::Op op) {
-  bool ret = SkCanvas::clipPath(path, op);
-  getTopPlatformDevice().SetClipRegion(getTotalClip());
-  return ret;
-}
-
-bool PlatformCanvasMac::clipRegion(const SkRegion& deviceRgn, SkRegion::Op op) {
-  bool ret = SkCanvas::clipRegion(deviceRgn, op);
-  getTopPlatformDevice().SetClipRegion(getTotalClip());
-  return ret;
-}
-
-// Transforming ---------------------------------------------------------------
-
-bool PlatformCanvasMac::translate(SkScalar dx, SkScalar dy) {
-  if (!SkCanvas::translate(dx, dy))
-    return false;
-  getTopPlatformDevice().SetTransform(getTotalMatrix());
-  return true;
-}
-
-bool PlatformCanvasMac::scale(SkScalar sx, SkScalar sy) {
-  if (!SkCanvas::scale(sx, sy))
-    return false;
-  getTopPlatformDevice().SetTransform(getTotalMatrix());
-  return true;
-}
-
-int PlatformCanvasMac::saveLayer(const SkRect* bounds,
-                              const SkPaint* paint,
-                              SaveFlags flags) {
-  int result = SkCanvas::saveLayer(bounds, paint, flags);
-
-  // saveLayer will have created a new device which, depending on the clip
-  // rect, may be smaller than the original layer. Therefore, it will have a
-  // transform applied, and we need to sync CG with that transform.
-  SkCanvas::LayerIter iter(this, false);
-  PlatformDeviceMac& new_device =
-      *static_cast<PlatformDeviceMac*>(iter.device());
-
-  // There man not actually be a new layer if the layer is empty.
-  if (!iter.done()) {
-    new_device.SetTransform(getTotalMatrix());
-    new_device.SetClipRegion(getTotalClip());
-  }
-  return result;
-}
-
-int PlatformCanvasMac::save(SkCanvas::SaveFlags flags) {
-  int ret = SkCanvas::save(flags);
-  PlatformDeviceMac& device = getTopPlatformDevice();
-  device.SetTransform(getTotalMatrix());
-  device.SetClipRegion(getTotalClip());
-  return ret;
-}
-
-void PlatformCanvasMac::restore() {
-  SkCanvas::restore();
-  PlatformDeviceMac& device = getTopPlatformDevice();
-  device.SetTransform(getTotalMatrix());
-  device.SetClipRegion(getTotalClip());
-}
-
 SkDevice* PlatformCanvasMac::createDevice(SkBitmap::Config config,
                                        int width,
                                        int height,
-                                       bool is_opaque) {
+                                       bool is_opaque, bool isForLayer) {
   DCHECK(config == SkBitmap::kARGB_8888_Config);
   return createPlatformDevice(width, height, is_opaque, NULL);
 }
diff --git a/base/gfx/platform_canvas_mac.h b/base/gfx/platform_canvas_mac.h
index 3cf2d5a..562b1a0 100755
--- a/base/gfx/platform_canvas_mac.h
+++ b/base/gfx/platform_canvas_mac.h
@@ -30,15 +30,6 @@ class PlatformCanvasMac : public SkCanvas {
   // For two-part init, call if you use the no-argument constructor above
   void initialize(int width, int height, bool is_opaque, CGContextRef context);
 
-  // Keep the platform clipping in sync with the skia clipping. Note that
-  // platform clipping may only clip to the bounds of the clipping region, if
-  // it is complex.
-  virtual bool clipRect(const SkRect& rect,
-                        SkRegion::Op op = SkRegion::kIntersect_Op);
-  virtual bool clipPath(const SkPath& path,
-                        SkRegion::Op op = SkRegion::kIntersect_Op);
-  virtual bool clipRegion(const SkRegion& deviceRgn,
-                          SkRegion::Op op = SkRegion::kIntersect_Op);
 
   // These calls should surround calls to platform drawing routines. The CG
   // context returned by beginPlatformPaint is the one that can be used to
@@ -48,14 +39,6 @@ class PlatformCanvasMac : public SkCanvas {
   virtual CGContextRef beginPlatformPaint();
   virtual void endPlatformPaint();
 
-  // overridden to keep the platform graphics context in sync with the canvas
-  virtual bool translate(SkScalar dx, SkScalar dy);
-  virtual bool scale(SkScalar sx, SkScalar sy);
-  virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
-                        SaveFlags flags = kARGB_ClipLayer_SaveFlag);
-  virtual int save(SkCanvas::SaveFlags flags = SkCanvas::kMatrixClip_SaveFlag);
-  virtual void restore();
-
   // Returns the platform device pointer of the topmost rect with a non-empty
   // clip. In practice, this is usually either the top layer or nothing, since
   // we usually set the clip to new layers when we make them.
@@ -80,7 +63,7 @@ class PlatformCanvasMac : public SkCanvas {
   // the device is always our own so we know that we can use GDI operations
   // on it. Simply calls into createPlatformDevice().
   virtual SkDevice* createDevice(SkBitmap::Config, int width, int height,
-                                 bool is_opaque);
+                                 bool is_opaque, bool isForLayer);
 
   // Creates a device store for use by the canvas. By default, it creates a
   // BitmapPlatformDevice object. Can be overridden to change the object type.
diff --git a/base/gfx/platform_device_mac.cc b/base/gfx/platform_device_mac.cc
index 9185dae..ab0b188 100755
--- a/base/gfx/platform_device_mac.cc
+++ b/base/gfx/platform_device_mac.cc
@@ -97,10 +97,73 @@ void PlatformDeviceMac::LoadPathToCGContext(CGContextRef context,
 // static
 void PlatformDeviceMac::LoadTransformToCGContext(CGContextRef context,
                                                  const SkMatrix& matrix) {
-  // TOOD: CoreGraphics can concatenate transforms, but not reset the current
-  // ont.  Either find a workaround or remove this function if it turns out
+  // TODO: CoreGraphics can concatenate transforms, but not reset the current
+  // one.  Either find a workaround or remove this function if it turns out
   // to be unneeded on the Mac.
+  // For now, just load the translation.
+  
+  // First reset the Transforms.
+  // TODO(playmobil): no need to call CGContextTranslateCTM() twice
+  // just add up the numbers and call through.
+  CGAffineTransform orig_transform = CGContextGetCTM(context);
+  CGContextTranslateCTM(context,
+                        -orig_transform.tx,
+                        orig_transform.ty);  // y axis is flipped.
+
+  // TODO(playmobil): remove debug code.
+  // CGAffineTransform temp_transform = CGContextGetCTM(context);
+  
+  // Now set the new transform.
+  int tx = matrix.getTranslateX();
+  int ty = -matrix.getTranslateY();
+  int height = CGBitmapContextGetHeight(context);
+  CGContextTranslateCTM(context,
+                        tx,
+                        -(ty+height));
+  CGAffineTransform new_transform = CGContextGetCTM(context);
+// TODO(playmobil): remove debug code.
+//  printf("tx_matrix (%lf,%lf)->(%lf,%lf)->(%lf,%lf) (%d, %d) height=%d\n", orig_transform.tx,
+//                                       orig_transform.ty,
+//                                       foo_transform.tx,
+//                                       foo_transform.ty,
+//                                       new_transform.tx,
+//                                       new_transform.ty, tx, ty, height);
 }
 
+// static
+void PlatformDeviceMac::LoadClippingRegionToCGContext(
+         CGContextRef context,
+         const SkRegion& region,
+         const SkMatrix& transformation) {
+  if (region.isEmpty()) {
+    // region can be empty, in which case everything will be clipped.
+    SkRect rect;
+    rect.setEmpty();
+    CGContextClipToRect(context, SkRectToCGRect(rect));
+  } else if (region.isRect()) {
+    // Do the transformation.
+    SkRect rect;
+    rect.set(region.getBounds());
+    transformation.mapRect(&rect);
+    SkIRect irect;
+    rect.round(&irect);
+// TODO(playmobil): remove debug code.
+//    printf("Clipping to (%d,%d) (%d,%d)\n", irect.fLeft, irect.fTop, 
+//           irect.fRight, irect.fBottom);
+    CGContextClipToRect(context, SkIRectToCGRect(irect));
+  } else {
+    // It is complex.
+    SkPath path;
+    region.getBoundaryPath(&path);
+    // Clip. Note that windows clipping regions are not affected by the
+    // transform so apply it manually.
+    path.transform(transformation);
+    // TODO(playmobil): Implement.
+    NOTREACHED();
+    // LoadPathToDC(context, path);
+    // hrgn = PathToRegion(context);
+  }
+}
+  
 }  // namespace gfx
 
diff --git a/base/gfx/platform_device_mac.h b/base/gfx/platform_device_mac.h
index 590cd24..79a14be 100755
--- a/base/gfx/platform_device_mac.h
+++ b/base/gfx/platform_device_mac.h
@@ -27,13 +27,6 @@ class PlatformDeviceMac : public SkDevice {
   // should exist only during one pass of rendering.
   virtual CGContextRef GetBitmapContext() = 0;
 
-  // Translate the device's coordinate system by the given amount; this will
-  // override any previous calls to this function.
-  virtual void SetTransform(const SkMatrix& matrix) = 0;
-
-  // Sets the clipping region, overriding any previous calls.
-  virtual void SetClipRegion(const SkRegion& region) = 0;
-
   // Draws to the given graphics context. If the bitmap context doesn't exist,
   // this will temporarily create it. However, if you have created the bitmap
   // context, it will be more efficient if you don't free it until after this
@@ -61,6 +54,11 @@ class PlatformDeviceMac : public SkDevice {
   // clipping or as a stroke.
   static void LoadPathToCGContext(CGContextRef context, const SkPath& path);
 
+  // Loads a SkRegion into the CG context.
+  static void LoadClippingRegionToCGContext(CGContextRef context, 
+                                            const SkRegion& region,
+                                            const SkMatrix& transformation);  
+  
  protected:
   // Forwards |bitmap| to SkDevice's constructor.
   PlatformDeviceMac(const SkBitmap& bitmap);
-- 
cgit v1.1