summaryrefslogtreecommitdiffstats
path: root/skia/ext
diff options
context:
space:
mode:
authorcaryclark@google.com <caryclark@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-29 16:42:31 +0000
committercaryclark@google.com <caryclark@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-29 16:42:31 +0000
commit992c290fdadd49115887ccedb75623822a4bf957 (patch)
tree43feda26b156f476a06f4d11f52bad0dd04196a3 /skia/ext
parente583e9c30e8fb77908872e7cf231b9af0ba32a31 (diff)
downloadchromium_src-992c290fdadd49115887ccedb75623822a4bf957.zip
chromium_src-992c290fdadd49115887ccedb75623822a4bf957.tar.gz
chromium_src-992c290fdadd49115887ccedb75623822a4bf957.tar.bz2
Pass the global matrix to CG always.
Draw the minimum. For both the cases when the canvas' device is bitmap-backed and when it is not, pass the global matrix to CG. When their was no backing bitmap, set the global matrix to identity (by concatenating the inverse). This allows multipage documents that adjust the global matrix by the height of the page to draw the bitmap that acts as a proxy for the device bits at the correct offset. Parse the built bitmap to find the bounds of the changed pixels, and draw that subset. BUG=121752 BUG=129527 TEST=http://jsfiddle.net/kqxBx/3/show/ (print to PDF) TEST=http://mrdoob.com/lab/javascript/checkbox_painter/ (print to PDF) TEST=SkiaUtilsMacTest.BitLocker_* Review URL: https://chromiumcodereview.appspot.com/10450024 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@139304 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia/ext')
-rw-r--r--skia/ext/skia_utils_mac.mm127
1 files changed, 101 insertions, 26 deletions
diff --git a/skia/ext/skia_utils_mac.mm b/skia/ext/skia_utils_mac.mm
index 48070d1..d8af9d0 100644
--- a/skia/ext/skia_utils_mac.mm
+++ b/skia/ext/skia_utils_mac.mm
@@ -307,7 +307,83 @@ void SkiaBitLocker::releaseIfNeeded() {
if (useDeviceBits_) {
bitmap_.unlockPixels();
} else {
- canvas_->drawBitmap(bitmap_, 0, 0);
+ // Find the bits that were drawn to.
+ SkAutoLockPixels lockedPixels(bitmap_);
+ const uint32_t* pixelBase
+ = reinterpret_cast<uint32_t*>(bitmap_.getPixels());
+ int rowPixels = bitmap_.rowBytesAsPixels();
+ int width = bitmap_.width();
+ int height = bitmap_.height();
+ SkIRect bounds;
+ bounds.fTop = 0;
+ int x;
+ int y = -1;
+ const uint32_t* pixels = pixelBase;
+ while (++y < height) {
+ for (x = 0; x < width; ++x) {
+ if (pixels[x]) {
+ bounds.fTop = y;
+ goto foundTop;
+ }
+ }
+ pixels += rowPixels;
+ }
+foundTop:
+ bounds.fBottom = height;
+ y = height;
+ pixels = pixelBase + rowPixels * (y - 1);
+ while (--y > bounds.fTop) {
+ for (x = 0; x < width; ++x) {
+ if (pixels[x]) {
+ bounds.fBottom = y + 1;
+ goto foundBottom;
+ }
+ }
+ pixels -= rowPixels;
+ }
+foundBottom:
+ bounds.fLeft = 0;
+ x = -1;
+ while (++x < width) {
+ pixels = pixelBase + rowPixels * bounds.fTop;
+ for (y = bounds.fTop; y < bounds.fBottom; ++y) {
+ if (pixels[x]) {
+ bounds.fLeft = x;
+ goto foundLeft;
+ }
+ pixels += rowPixels;
+ }
+ }
+foundLeft:
+ bounds.fRight = width;
+ x = width;
+ while (--x > bounds.fLeft) {
+ pixels = pixelBase + rowPixels * bounds.fTop;
+ for (y = bounds.fTop; y < bounds.fBottom; ++y) {
+ if (pixels[x]) {
+ bounds.fRight = x + 1;
+ goto foundRight;
+ }
+ pixels += rowPixels;
+ }
+ }
+foundRight:
+ SkBitmap subset;
+ if (!bitmap_.extractSubset(&subset, bounds)) {
+ return;
+ }
+ // Neutralize the global matrix by concatenating the inverse. In the
+ // future, Skia may provide some mechanism to set the device portion of
+ // the matrix to identity without clobbering any hosting matrix (e.g., the
+ // picture's matrix).
+ const SkMatrix& skMatrix = canvas_->getTotalMatrix();
+ SkMatrix inverse;
+ if (!skMatrix.invert(&inverse))
+ return;
+ canvas_->save();
+ canvas_->concat(inverse);
+ canvas_->drawBitmap(subset, bounds.fLeft, bounds.fTop);
+ canvas_->restore();
}
CGContextRelease(cgContext_);
cgContext_ = 0;
@@ -340,33 +416,32 @@ CGContextRef SkiaBitLocker::cgContext() {
-device->height());
CGContextConcatCTM(cgContext_, contentsTransform);
- // Skip applying the matrix and clip when not writing directly to device.
- // They're applied in the offscreen case when the bitmap is drawn.
- if (!useDeviceBits_) {
- return cgContext_;
- }
-
- // Apply clip in device coordinates.
- CGMutablePathRef clipPath = CGPathCreateMutable();
- const SkRegion& clipRgn = canvas_->getTotalClip();
- if (clipRgn.isEmpty()) {
- // CoreGraphics does not consider a newly created path to be empty.
- // Explicitly set it to empty so the subsequent drawing is clipped out.
- // It would be better to make the CGContext hidden if there was a CG call
- // that does that.
- CGPathAddRect(clipPath, 0, CGRectMake(0, 0, 0, 0));
- }
- SkRegion::Iterator iter(clipRgn);
const SkIPoint& pt = device->getOrigin();
- for (; !iter.done(); iter.next()) {
- SkIRect skRect = iter.rect();
- skRect.offset(-pt);
- CGRect cgRect = SkIRectToCGRect(skRect);
- CGPathAddRect(clipPath, 0, cgRect);
+ // Skip applying the clip when not writing directly to device.
+ // They're applied in the offscreen case when the bitmap is drawn.
+ if (useDeviceBits_) {
+ // Apply clip in device coordinates.
+ CGMutablePathRef clipPath = CGPathCreateMutable();
+ const SkRegion& clipRgn = canvas_->getTotalClip();
+ if (clipRgn.isEmpty()) {
+ // CoreGraphics does not consider a newly created path to be empty.
+ // Explicitly set it to empty so the subsequent drawing is clipped out.
+ // It would be better to make the CGContext hidden if there was a CG
+ // call that does that.
+ CGPathAddRect(clipPath, 0, CGRectMake(0, 0, 0, 0));
+ }
+ SkRegion::Iterator iter(clipRgn);
+ const SkIPoint& pt = device->getOrigin();
+ for (; !iter.done(); iter.next()) {
+ SkIRect skRect = iter.rect();
+ skRect.offset(-pt);
+ CGRect cgRect = SkIRectToCGRect(skRect);
+ CGPathAddRect(clipPath, 0, cgRect);
+ }
+ CGContextAddPath(cgContext_, clipPath);
+ CGContextClip(cgContext_);
+ CGPathRelease(clipPath);
}
- CGContextAddPath(cgContext_, clipPath);
- CGContextClip(cgContext_);
- CGPathRelease(clipPath);
// Apply content matrix.
SkMatrix skMatrix = canvas_->getTotalMatrix();