1e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
2e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com/*
3e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com * Copyright 2012 Google Inc.
4e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com *
5e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com * Use of this source code is governed by a BSD-style license that can be
6e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com * found in the LICENSE file.
7e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com */
8e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
9e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com#include "SkBBoxRecord.h"
10b3c9d1c33caf325aada244204215eb790c228c12dandov#include "SkPatchUtils.h"
11e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
12b7425173f96e93b090787e2386ba5f022b6c2869fmalita#include "SkTextBlob.h"
13b7425173f96e93b090787e2386ba5f022b6c2869fmalita
14837f5321a409228a27fc710eb71c87866b820cfbsenorblancoSkBBoxRecord::~SkBBoxRecord() {
15837f5321a409228a27fc710eb71c87866b820cfbsenorblanco    fSaveStack.deleteAll();
16837f5321a409228a27fc710eb71c87866b820cfbsenorblanco}
17837f5321a409228a27fc710eb71c87866b820cfbsenorblanco
185f8c8f448673c65c5434cf1e419319eccf34117bjunov@chromium.orgvoid SkBBoxRecord::drawOval(const SkRect& rect, const SkPaint& paint) {
195f8c8f448673c65c5434cf1e419319eccf34117bjunov@chromium.org    if (this->transformBounds(rect, &paint)) {
205f8c8f448673c65c5434cf1e419319eccf34117bjunov@chromium.org        INHERITED::drawOval(rect, paint);
215f8c8f448673c65c5434cf1e419319eccf34117bjunov@chromium.org    }
225f8c8f448673c65c5434cf1e419319eccf34117bjunov@chromium.org}
235f8c8f448673c65c5434cf1e419319eccf34117bjunov@chromium.org
245f8c8f448673c65c5434cf1e419319eccf34117bjunov@chromium.orgvoid SkBBoxRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
255f8c8f448673c65c5434cf1e419319eccf34117bjunov@chromium.org    if (this->transformBounds(rrect.rect(), &paint)) {
265f8c8f448673c65c5434cf1e419319eccf34117bjunov@chromium.org        INHERITED::drawRRect(rrect, paint);
275f8c8f448673c65c5434cf1e419319eccf34117bjunov@chromium.org    }
285f8c8f448673c65c5434cf1e419319eccf34117bjunov@chromium.org}
295f8c8f448673c65c5434cf1e419319eccf34117bjunov@chromium.org
307ce564cccb246ec56427085872b2e1458fe74bd1bsalomon@google.comvoid SkBBoxRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
31e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    if (this->transformBounds(rect, &paint)) {
327ce564cccb246ec56427085872b2e1458fe74bd1bsalomon@google.com        INHERITED::drawRect(rect, paint);
33e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
34e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com}
35e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
36ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.orgvoid SkBBoxRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
37ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.org                                const SkPaint& paint) {
38ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.org    if (this->transformBounds(outer.rect(), &paint)) {
39ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.org        this->INHERITED::onDrawDRRect(outer, inner, paint);
40ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.org    }
41ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.org}
42ed9806f5c972513d4141c9d1b5a04ab78b3af4cbcommit-bot@chromium.org
437ce564cccb246ec56427085872b2e1458fe74bd1bsalomon@google.comvoid SkBBoxRecord::drawPath(const SkPath& path, const SkPaint& paint) {
440c8ec2f658a206cbedd0d955167654fae85ad5fbjunov@chromium.org    if (path.isInverseFillType()) {
450c8ec2f658a206cbedd0d955167654fae85ad5fbjunov@chromium.org        // If path is inverse filled, use the current clip bounds as the
460c8ec2f658a206cbedd0d955167654fae85ad5fbjunov@chromium.org        // path's device-space bounding box.
470c8ec2f658a206cbedd0d955167654fae85ad5fbjunov@chromium.org        SkIRect clipBounds;
480c8ec2f658a206cbedd0d955167654fae85ad5fbjunov@chromium.org        if (this->getClipDeviceBounds(&clipBounds)) {
494469938e92d779dff05e745559e67907bbf21e78reed@google.com            this->handleBBox(SkRect::Make(clipBounds));
507ce564cccb246ec56427085872b2e1458fe74bd1bsalomon@google.com            INHERITED::drawPath(path, paint);
510c8ec2f658a206cbedd0d955167654fae85ad5fbjunov@chromium.org        }
520c8ec2f658a206cbedd0d955167654fae85ad5fbjunov@chromium.org    } else if (this->transformBounds(path.getBounds(), &paint)) {
537ce564cccb246ec56427085872b2e1458fe74bd1bsalomon@google.com        INHERITED::drawPath(path, paint);
54e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
55e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com}
56e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
57e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.comvoid SkBBoxRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
58e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com                              const SkPaint& paint) {
59e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    SkRect bbox;
606fcd28ba1de83b72f4c8343ccec27d26c127de32reed@google.com    bbox.set(pts, SkToInt(count));
61b3470c8c421ee8f367673a67c3408507cee04434junov@chromium.org    // Small min width value, just to ensure hairline point bounding boxes aren't empty.
62b3470c8c421ee8f367673a67c3408507cee04434junov@chromium.org    // Even though we know hairline primitives are drawn one pixel wide, we do not use a
63b3470c8c421ee8f367673a67c3408507cee04434junov@chromium.org    // minimum of 1 because the playback scale factor is unknown at record time. Later
64b3470c8c421ee8f367673a67c3408507cee04434junov@chromium.org    // outsets will take care of adding additional padding for antialiasing and rounding out
65b3470c8c421ee8f367673a67c3408507cee04434junov@chromium.org    // to integer device coordinates, guaranteeing that the rasterized pixels will be included
66b3470c8c421ee8f367673a67c3408507cee04434junov@chromium.org    // in the computed bounds.
67b3470c8c421ee8f367673a67c3408507cee04434junov@chromium.org    // Note: The device coordinate outset in SkBBoxHierarchyRecord::handleBBox is currently
68b3470c8c421ee8f367673a67c3408507cee04434junov@chromium.org    // done in the recording coordinate space, which is wrong.
69b3470c8c421ee8f367673a67c3408507cee04434junov@chromium.org    // http://code.google.com/p/skia/issues/detail?id=1021
704b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org    static const SkScalar kMinWidth = 0.01f;
71b3470c8c421ee8f367673a67c3408507cee04434junov@chromium.org    SkScalar halfStrokeWidth = SkMaxScalar(paint.getStrokeWidth(), kMinWidth) / 2;
72b3470c8c421ee8f367673a67c3408507cee04434junov@chromium.org    bbox.outset(halfStrokeWidth, halfStrokeWidth);
73e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    if (this->transformBounds(bbox, &paint)) {
74e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        INHERITED::drawPoints(mode, count, pts, paint);
75e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
7604ba448579b976369075c675d847ef0f779d40f4skia.committer@gmail.com}
77e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
78e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.comvoid SkBBoxRecord::drawPaint(const SkPaint& paint) {
79e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    SkRect bbox;
80e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    if (this->getClipBounds(&bbox)) {
81e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        if (this->transformBounds(bbox, &paint)) {
82e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com            INHERITED::drawPaint(paint);
83e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        }
84e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
85e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com}
86e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
87e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.comvoid SkBBoxRecord::clear(SkColor color) {
88e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    SkISize size = this->getDeviceSize();
89ec0aa764ebe36aecdfb77286d665fccc85ab204ageorge@mozilla.com    SkRect bbox = {0, 0, SkIntToScalar(size.width()), SkIntToScalar(size.height())};
90e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    this->handleBBox(bbox);
91e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    INHERITED::clear(color);
92e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com}
93e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
94e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.comvoid SkBBoxRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
95e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com                              const SkPaint& paint) {
96e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    SkRect bbox;
97e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    paint.measureText(text, byteLength, &bbox);
98e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    SkPaint::FontMetrics metrics;
99e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    paint.getFontMetrics(&metrics);
100e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
101e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    // Vertical and aligned text need to be offset
102e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    if (paint.isVerticalText()) {
103e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        SkScalar h = bbox.fBottom - bbox.fTop;
104e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
105e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com            bbox.fTop    -= h / 2;
106e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com            bbox.fBottom -= h / 2;
107e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        }
108e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        // Pad top and bottom with max extents from FontMetrics
109e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        bbox.fBottom += metrics.fBottom;
110e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        bbox.fTop += metrics.fTop;
111e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    } else {
112e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        SkScalar w = bbox.fRight - bbox.fLeft;
113e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
114e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com            bbox.fLeft  -= w / 2;
115e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com            bbox.fRight -= w / 2;
116e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
117e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com            bbox.fLeft  -= w;
118e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com            bbox.fRight -= w;
119e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        }
120e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        // Set vertical bounds to max extents from font metrics
121e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        bbox.fTop = metrics.fTop;
122e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        bbox.fBottom = metrics.fBottom;
123e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
124e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
12504ba448579b976369075c675d847ef0f779d40f4skia.committer@gmail.com    // Pad horizontal bounds on each side by half of max vertical extents (this is sort of
126e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    // arbitrary, but seems to produce reasonable results, if there were a way of getting max
127e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    // glyph X-extents to pad by, that may be better here, but FontMetrics fXMin and fXMax seem
128e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    // incorrect on most platforms (too small in Linux, never even set in Windows).
129e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
130e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    bbox.fLeft  -= pad;
131e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    bbox.fRight += pad;
132e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
133e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    bbox.fLeft += x;
134e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    bbox.fRight += x;
135e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    bbox.fTop += y;
136e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    bbox.fBottom += y;
137e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    if (this->transformBounds(bbox, &paint)) {
138e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com        INHERITED::onDrawText(text, byteLength, x, y, paint);
139e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
140e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com}
141e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
142e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.comvoid SkBBoxRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
143e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com                              const SkPaint* paint) {
144e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    SkRect bbox = {left, top, left + bitmap.width(), top + bitmap.height()};
145e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    if (this->transformBounds(bbox, paint)) {
146e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        INHERITED::drawBitmap(bitmap, left, top, paint);
147e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
148e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com}
149e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
1507112173c3c4cd1b1e7da8cdf971d71f01dd91299reed@google.comvoid SkBBoxRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
151eed779d866e1e239bfb9ebc6a225b7345a41adf9commit-bot@chromium.org                                        const SkRect& dst, const SkPaint* paint,
152eed779d866e1e239bfb9ebc6a225b7345a41adf9commit-bot@chromium.org                                        DrawBitmapRectFlags flags) {
153e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    if (this->transformBounds(dst, paint)) {
154eed779d866e1e239bfb9ebc6a225b7345a41adf9commit-bot@chromium.org        INHERITED::drawBitmapRectToRect(bitmap, src, dst, paint, flags);
155e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
156e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com}
157e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
158e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.comvoid SkBBoxRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& mat,
159e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com                                    const SkPaint* paint) {
160e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    SkMatrix m = mat;
161ec0aa764ebe36aecdfb77286d665fccc85ab204ageorge@mozilla.com    SkRect bbox = {0, 0, SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())};
162e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    m.mapRect(&bbox);
163e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    if (this->transformBounds(bbox, paint)) {
164e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        INHERITED::drawBitmapMatrix(bitmap, mat, paint);
165e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
166e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com}
167e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
168e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.comvoid SkBBoxRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
169e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com                                  const SkRect& dst, const SkPaint* paint) {
170e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    if (this->transformBounds(dst, paint)) {
171e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        INHERITED::drawBitmapNine(bitmap, center, dst, paint);
172e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
173e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com}
174e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
175300790e228751661e1245c774b967b6cc50ffa1bcommit-bot@chromium.org// Hack to work-around https://code.google.com/p/chromium/issues/detail?id=373785
176300790e228751661e1245c774b967b6cc50ffa1bcommit-bot@chromium.org// This logic assums that 'pad' is enough to add to the left and right to account for
177300790e228751661e1245c774b967b6cc50ffa1bcommit-bot@chromium.org// big glyphs. For the font in question (a logo font) the glyphs is much wider than just
178300790e228751661e1245c774b967b6cc50ffa1bcommit-bot@chromium.org// the pointsize (approx 3x wider).
179300790e228751661e1245c774b967b6cc50ffa1bcommit-bot@chromium.org// As a temp work-around, we scale-up pad.
180300790e228751661e1245c774b967b6cc50ffa1bcommit-bot@chromium.org// A more correct fix might be to add fontmetrics.fMaxX, but we don't have that value in hand
181300790e228751661e1245c774b967b6cc50ffa1bcommit-bot@chromium.org// at the moment, and (possibly) the value in the font may not be accurate (but who knows).
182300790e228751661e1245c774b967b6cc50ffa1bcommit-bot@chromium.org//
183300790e228751661e1245c774b967b6cc50ffa1bcommit-bot@chromium.orgstatic SkScalar hack_373785_amend_pad(SkScalar pad) {
184300790e228751661e1245c774b967b6cc50ffa1bcommit-bot@chromium.org    return pad * 4;
185300790e228751661e1245c774b967b6cc50ffa1bcommit-bot@chromium.org}
186300790e228751661e1245c774b967b6cc50ffa1bcommit-bot@chromium.org
187e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.comvoid SkBBoxRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
188e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com                                 const SkPaint& paint) {
189e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    SkRect bbox;
190e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    bbox.set(pos, paint.countText(text, byteLength));
191e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    SkPaint::FontMetrics metrics;
192e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    paint.getFontMetrics(&metrics);
193e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    bbox.fTop += metrics.fTop;
194e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    bbox.fBottom += metrics.fBottom;
195e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
196e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    // pad on left and right by half of max vertical glyph extents
197e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
198300790e228751661e1245c774b967b6cc50ffa1bcommit-bot@chromium.org    pad = hack_373785_amend_pad(pad);
199e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    bbox.fLeft += pad;
200e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    bbox.fRight -= pad;
201e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
202e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    if (this->transformBounds(bbox, &paint)) {
203e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com        INHERITED::onDrawPosText(text, byteLength, pos, paint);
204e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
205e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com}
206e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
207e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.comvoid SkBBoxRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
208e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com                                  SkScalar constY, const SkPaint& paint) {
209e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    size_t numChars = paint.countText(text, byteLength);
210cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    if (numChars == 0) {
211cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org        return;
212cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    }
213cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org
214cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
215cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    WriteTopBot(paint, *flatPaintData);
216cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org
217cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    SkScalar top = flatPaintData->topBot()[0];
218cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    SkScalar bottom = flatPaintData->topBot()[1];
219cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    SkScalar pad = top - bottom;
220cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org
221cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    SkRect bbox;
222cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    bbox.fLeft = SK_ScalarMax;
223cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    bbox.fRight = SK_ScalarMin;
224cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org
225cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    for (size_t i = 0; i < numChars; ++i) {
226cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org        if (xpos[i] < bbox.fLeft) {
227cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org            bbox.fLeft = xpos[i];
228e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        }
229cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org        if (xpos[i] > bbox.fRight) {
230cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org            bbox.fRight = xpos[i];
231e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        }
232e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
233cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org
234cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    // pad horizontally by max glyph height
235300790e228751661e1245c774b967b6cc50ffa1bcommit-bot@chromium.org    pad = hack_373785_amend_pad(pad);
236cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    bbox.fLeft  += pad;
237cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    bbox.fRight -= pad;
238cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org
239cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    bbox.fTop    = top + constY;
240cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    bbox.fBottom = bottom + constY;
241cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org
242cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    if (!this->transformBounds(bbox, &paint)) {
243cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org        return;
244cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    }
245cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    // This is the equivalent of calling:
246cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    //  INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint);
247cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    // but we filled our flat paint beforehand so that we could get font metrics.
248cf7be95b19f283e3c5410f977474f433a1e10dadcommit-bot@chromium.org    drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
249e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com}
250e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
251e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.comvoid SkBBoxRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
252e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com                              const SkPaint* paint) {
25378c0c30987075821547979de55200c32bcaa3e49junov@chromium.org    SkRect bbox;
25478c0c30987075821547979de55200c32bcaa3e49junov@chromium.org    bbox.set(SkIRect::MakeXYWH(left, top, bitmap.width(), bitmap.height()));
255e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    this->handleBBox(bbox); // directly call handleBBox, matrix is ignored
25678c0c30987075821547979de55200c32bcaa3e49junov@chromium.org    INHERITED::drawSprite(bitmap, left, top, paint);
257e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com}
258e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
259e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.comvoid SkBBoxRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
260e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com                                    const SkMatrix* matrix, const SkPaint& paint) {
261e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    SkRect bbox = path.getBounds();
262e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    SkPaint::FontMetrics metrics;
263e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    paint.getFontMetrics(&metrics);
264e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
265e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    // pad out all sides by the max glyph height above baseline
266e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    SkScalar pad = metrics.fTop;
267e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    bbox.fLeft += pad;
268e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    bbox.fRight -= pad;
269e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    bbox.fTop += pad;
270e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    bbox.fBottom -= pad;
271e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
272e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    if (this->transformBounds(bbox, &paint)) {
273e0d9ce890e67d02727ac2811bb456ddb64f827d4reed@google.com        INHERITED::onDrawTextOnPath(text, byteLength, path, matrix, paint);
274e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
275e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com}
276e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
277b7425173f96e93b090787e2386ba5f022b6c2869fmalitavoid SkBBoxRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
278b7425173f96e93b090787e2386ba5f022b6c2869fmalita                                  const SkPaint& paint) {
279b7425173f96e93b090787e2386ba5f022b6c2869fmalita    SkRect bbox = blob->bounds();
280b7425173f96e93b090787e2386ba5f022b6c2869fmalita    bbox.offset(x, y);
281b7425173f96e93b090787e2386ba5f022b6c2869fmalita    // FIXME: implement implicit blob bounds!
282b7425173f96e93b090787e2386ba5f022b6c2869fmalita    if (bbox.isEmpty()) {
283b7425173f96e93b090787e2386ba5f022b6c2869fmalita        this->getClipBounds(&bbox);
284b7425173f96e93b090787e2386ba5f022b6c2869fmalita    }
285b7425173f96e93b090787e2386ba5f022b6c2869fmalita
286b7425173f96e93b090787e2386ba5f022b6c2869fmalita    if (this->transformBounds(bbox, &paint)) {
287b7425173f96e93b090787e2386ba5f022b6c2869fmalita        INHERITED::onDrawTextBlob(blob, x, y, paint);
288b7425173f96e93b090787e2386ba5f022b6c2869fmalita    }
289b7425173f96e93b090787e2386ba5f022b6c2869fmalita}
290b7425173f96e93b090787e2386ba5f022b6c2869fmalita
291e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.comvoid SkBBoxRecord::drawVertices(VertexMode mode, int vertexCount,
292e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com                                const SkPoint vertices[], const SkPoint texs[],
293e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com                                const SkColor colors[], SkXfermode* xfer,
294e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com                                const uint16_t indices[], int indexCount,
295e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com                                const SkPaint& paint) {
296e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    SkRect bbox;
297e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    bbox.set(vertices, vertexCount);
298e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    if (this->transformBounds(bbox, &paint)) {
299e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        INHERITED::drawVertices(mode, vertexCount, vertices, texs,
300e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com                                colors, xfer, indices, indexCount, paint);
301e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
302e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com}
303e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
304b3c9d1c33caf325aada244204215eb790c228c12dandovvoid SkBBoxRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
305b3c9d1c33caf325aada244204215eb790c228c12dandov                               const SkPoint texCoords[4], SkXfermode* xmode,
306b3c9d1c33caf325aada244204215eb790c228c12dandov                               const SkPaint& paint) {
307963137b75c0a1fe91f35e9826742f36309f5e65ddandov    SkRect bbox;
308b3c9d1c33caf325aada244204215eb790c228c12dandov    bbox.set(cubics, SkPatchUtils::kNumCtrlPts);
309963137b75c0a1fe91f35e9826742f36309f5e65ddandov    if (this->transformBounds(bbox, &paint)) {
310b3c9d1c33caf325aada244204215eb790c228c12dandov        INHERITED::onDrawPatch(cubics, colors, texCoords, xmode, paint);
311963137b75c0a1fe91f35e9826742f36309f5e65ddandov    }
312963137b75c0a1fe91f35e9826742f36309f5e65ddandov}
313963137b75c0a1fe91f35e9826742f36309f5e65ddandov
314d5fa1a455aad61f3e99081fe7a9b065cb3b115c6reedvoid SkBBoxRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
315d5fa1a455aad61f3e99081fe7a9b065cb3b115c6reed                                 const SkPaint* paint) {
316a8d7f0b13cd4c6d773fcf055fe17db75d260fa05robertphillips    SkRect bounds = picture->cullRect();
317d5fa1a455aad61f3e99081fe7a9b065cb3b115c6reed    // todo: wonder if we should allow passing an optional matrix to transformBounds so we don't
318d5fa1a455aad61f3e99081fe7a9b065cb3b115c6reed    // end up transforming the rect twice.
319d5fa1a455aad61f3e99081fe7a9b065cb3b115c6reed    if (matrix) {
320d5fa1a455aad61f3e99081fe7a9b065cb3b115c6reed        matrix->mapRect(&bounds);
321d5fa1a455aad61f3e99081fe7a9b065cb3b115c6reed    }
322d5fa1a455aad61f3e99081fe7a9b065cb3b115c6reed    if (this->transformBounds(bounds, paint)) {
323d5fa1a455aad61f3e99081fe7a9b065cb3b115c6reed        this->INHERITED::onDrawPicture(picture, matrix, paint);
324e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
325e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com}
326e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
327837f5321a409228a27fc710eb71c87866b820cfbsenorblancovoid SkBBoxRecord::willSave() {
328837f5321a409228a27fc710eb71c87866b820cfbsenorblanco    fSaveStack.push(NULL);
329837f5321a409228a27fc710eb71c87866b820cfbsenorblanco    this->INHERITED::willSave();
330837f5321a409228a27fc710eb71c87866b820cfbsenorblanco}
331837f5321a409228a27fc710eb71c87866b820cfbsenorblanco
332837f5321a409228a27fc710eb71c87866b820cfbsenorblancoSkCanvas::SaveLayerStrategy SkBBoxRecord::willSaveLayer(const SkRect* bounds,
333837f5321a409228a27fc710eb71c87866b820cfbsenorblanco                                                        const SkPaint* paint,
334837f5321a409228a27fc710eb71c87866b820cfbsenorblanco                                                        SaveFlags flags) {
335837f5321a409228a27fc710eb71c87866b820cfbsenorblanco    // Image filters can affect the effective bounds of primitives drawn inside saveLayer().
336837f5321a409228a27fc710eb71c87866b820cfbsenorblanco    // Copy the paint so we can compute the modified bounds in transformBounds().
337837f5321a409228a27fc710eb71c87866b820cfbsenorblanco    fSaveStack.push(paint && paint->getImageFilter() ? new SkPaint(*paint) : NULL);
338837f5321a409228a27fc710eb71c87866b820cfbsenorblanco    return this->INHERITED::willSaveLayer(bounds, paint, flags);
339837f5321a409228a27fc710eb71c87866b820cfbsenorblanco}
340837f5321a409228a27fc710eb71c87866b820cfbsenorblanco
341837f5321a409228a27fc710eb71c87866b820cfbsenorblancovoid SkBBoxRecord::willRestore() {
342837f5321a409228a27fc710eb71c87866b820cfbsenorblanco    delete fSaveStack.top();
343837f5321a409228a27fc710eb71c87866b820cfbsenorblanco    fSaveStack.pop();
344837f5321a409228a27fc710eb71c87866b820cfbsenorblanco    this->INHERITED::willRestore();
345837f5321a409228a27fc710eb71c87866b820cfbsenorblanco}
346837f5321a409228a27fc710eb71c87866b820cfbsenorblanco
347e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.combool SkBBoxRecord::transformBounds(const SkRect& bounds, const SkPaint* paint) {
348e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    SkRect outBounds = bounds;
3496006b5641e575181f2d6f1212b8db491b2c2671cjunov@chromium.org    outBounds.sort();
350e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
351e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    if (paint) {
352e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        // account for stroking, path effects, shadows, etc
353e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        if (paint->canComputeFastBounds()) {
354e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com            SkRect temp;
3556006b5641e575181f2d6f1212b8db491b2c2671cjunov@chromium.org            outBounds = paint->computeFastBounds(outBounds, &temp);
356e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        } else {
357e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com            // set bounds to current clip
358e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com            if (!this->getClipBounds(&outBounds)) {
359e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com                // current clip is empty
360e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com                return false;
361e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com            }
362e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        }
363e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
364e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
365837f5321a409228a27fc710eb71c87866b820cfbsenorblanco    for (int i = fSaveStack.count() - 1; i >= 0; --i) {
366837f5321a409228a27fc710eb71c87866b820cfbsenorblanco        const SkPaint* paint = fSaveStack.getAt(i);
367837f5321a409228a27fc710eb71c87866b820cfbsenorblanco        if (paint && paint->canComputeFastBounds()) {
368837f5321a409228a27fc710eb71c87866b820cfbsenorblanco            SkRect temp;
369837f5321a409228a27fc710eb71c87866b820cfbsenorblanco            outBounds = paint->computeFastBounds(outBounds, &temp);
370837f5321a409228a27fc710eb71c87866b820cfbsenorblanco        }
371837f5321a409228a27fc710eb71c87866b820cfbsenorblanco    }
372837f5321a409228a27fc710eb71c87866b820cfbsenorblanco
37359a6a2b98302adc4732fc26873043bad1a94e9f1bungeman@google.com    if (!outBounds.isEmpty() && !this->quickReject(outBounds)) {
374e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        this->getTotalMatrix().mapRect(&outBounds);
375e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        this->handleBBox(outBounds);
376e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com        return true;
377e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    }
378e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com
379e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com    return false;
380e0201a4448f5e770cc081ca3425bed528af27f8drileya@google.com}
381