diff options
author | caryclark@google.com <caryclark@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-29 16:42:31 +0000 |
---|---|---|
committer | caryclark@google.com <caryclark@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-29 16:42:31 +0000 |
commit | 992c290fdadd49115887ccedb75623822a4bf957 (patch) | |
tree | 43feda26b156f476a06f4d11f52bad0dd04196a3 /skia/ext | |
parent | e583e9c30e8fb77908872e7cf231b9af0ba32a31 (diff) | |
download | chromium_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.mm | 127 |
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(); |