SkBBoxRecord.cpp revision 04ba448579b976369075c675d847ef0f779d40f4
1
2/*
3 * Copyright 2012 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "SkBBoxRecord.h"
10
11void SkBBoxRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
12    if (this->transformBounds(rect, &paint)) {
13        INHERITED::drawRect(rect, paint);
14    }
15}
16
17void SkBBoxRecord::drawPath(const SkPath& path, const SkPaint& paint) {
18    if (this->transformBounds(path.getBounds(), &paint)) {
19        INHERITED::drawPath(path, paint);
20    }
21}
22
23void SkBBoxRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
24                              const SkPaint& paint) {
25    SkRect bbox;
26    bbox.set(pts, count);
27    if (this->transformBounds(bbox, &paint)) {
28        INHERITED::drawPoints(mode, count, pts, paint);
29    }
30}
31
32void SkBBoxRecord::drawPaint(const SkPaint& paint) {
33    SkRect bbox;
34    if (this->getClipBounds(&bbox)) {
35        if (this->transformBounds(bbox, &paint)) {
36            INHERITED::drawPaint(paint);
37        }
38    }
39}
40
41void SkBBoxRecord::clear(SkColor color) {
42    SkISize size = this->getDeviceSize();
43    SkRect bbox = {0, 0, size.width(), size.height()};
44    this->handleBBox(bbox);
45    INHERITED::clear(color);
46}
47
48void SkBBoxRecord::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
49                            const SkPaint& paint) {
50    SkRect bbox;
51    paint.measureText(text, byteLength, &bbox);
52    SkPaint::FontMetrics metrics;
53    paint.getFontMetrics(&metrics);
54
55    // Vertical and aligned text need to be offset
56    if (paint.isVerticalText()) {
57        SkScalar h = bbox.fBottom - bbox.fTop;
58        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
59            bbox.fTop    -= h / 2;
60            bbox.fBottom -= h / 2;
61        }
62        // Pad top and bottom with max extents from FontMetrics
63        bbox.fBottom += metrics.fBottom;
64        bbox.fTop += metrics.fTop;
65    } else {
66        SkScalar w = bbox.fRight - bbox.fLeft;
67        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
68            bbox.fLeft  -= w / 2;
69            bbox.fRight -= w / 2;
70        } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
71            bbox.fLeft  -= w;
72            bbox.fRight -= w;
73        }
74        // Set vertical bounds to max extents from font metrics
75        bbox.fTop = metrics.fTop;
76        bbox.fBottom = metrics.fBottom;
77    }
78
79    // Pad horizontal bounds on each side by half of max vertical extents (this is sort of
80    // arbitrary, but seems to produce reasonable results, if there were a way of getting max
81    // glyph X-extents to pad by, that may be better here, but FontMetrics fXMin and fXMax seem
82    // incorrect on most platforms (too small in Linux, never even set in Windows).
83    SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
84    bbox.fLeft  -= pad;
85    bbox.fRight += pad;
86
87    bbox.fLeft += x;
88    bbox.fRight += x;
89    bbox.fTop += y;
90    bbox.fBottom += y;
91    if (this->transformBounds(bbox, &paint)) {
92        INHERITED::drawText(text, byteLength, x, y, paint);
93    }
94}
95
96void SkBBoxRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
97                              const SkPaint* paint) {
98    SkRect bbox = {left, top, left + bitmap.width(), top + bitmap.height()};
99    if (this->transformBounds(bbox, paint)) {
100        INHERITED::drawBitmap(bitmap, left, top, paint);
101    }
102}
103
104void SkBBoxRecord::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
105                                  const SkRect& dst, const SkPaint* paint) {
106    if (this->transformBounds(dst, paint)) {
107        INHERITED::drawBitmapRect(bitmap, src, dst, paint);
108    }
109}
110
111void SkBBoxRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& mat,
112                                    const SkPaint* paint) {
113    SkMatrix m = mat;
114    SkRect bbox = {0, 0, bitmap.width(), bitmap.height()};
115    m.mapRect(&bbox);
116    if (this->transformBounds(bbox, paint)) {
117        INHERITED::drawBitmapMatrix(bitmap, mat, paint);
118    }
119}
120
121void SkBBoxRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
122                                  const SkRect& dst, const SkPaint* paint) {
123    if (this->transformBounds(dst, paint)) {
124        INHERITED::drawBitmapNine(bitmap, center, dst, paint);
125    }
126}
127
128void SkBBoxRecord::drawPosText(const void* text, size_t byteLength,
129                               const SkPoint pos[], const SkPaint& paint) {
130    SkRect bbox;
131    bbox.set(pos, paint.countText(text, byteLength));
132    SkPaint::FontMetrics metrics;
133    paint.getFontMetrics(&metrics);
134    bbox.fTop += metrics.fTop;
135    bbox.fBottom += metrics.fBottom;
136
137    // pad on left and right by half of max vertical glyph extents
138    SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
139    bbox.fLeft += pad;
140    bbox.fRight -= pad;
141
142    if (this->transformBounds(bbox, &paint)) {
143        INHERITED::drawPosText(text, byteLength, pos, paint);
144    }
145}
146
147void SkBBoxRecord::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
148                                SkScalar constY, const SkPaint& paint) {
149    SkRect bbox;
150    size_t numChars = paint.countText(text, byteLength);
151    if (numChars > 0) {
152        bbox.fLeft  = xpos[0];
153        bbox.fRight = xpos[numChars - 1];
154        // if we had a guarantee that these will be monotonically increasing, this could be sped up
155        for (size_t i = 1; i < numChars; ++i) {
156            if (xpos[i] < bbox.fLeft) {
157                bbox.fLeft = xpos[i];
158            }
159            if (xpos[i] > bbox.fRight) {
160                bbox.fRight = xpos[i];
161            }
162        }
163        SkPaint::FontMetrics metrics;
164        paint.getFontMetrics(&metrics);
165
166        // pad horizontally by half max glyph height
167        SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
168        bbox.fLeft  += pad;
169        bbox.fRight -= pad;
170
171        bbox.fTop    = metrics.fTop + constY;
172        bbox.fBottom = metrics.fBottom + constY;
173        if (!this->transformBounds(bbox, &paint)) {
174            return;
175        }
176    }
177    INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint);
178}
179
180void SkBBoxRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
181                              const SkPaint* paint) {
182    SkRect bbox = {left, top, left + bitmap.width(), top + bitmap.height()};
183    this->handleBBox(bbox); // directly call handleBBox, matrix is ignored
184    INHERITED::drawBitmap(bitmap, left, top, paint);
185}
186
187void SkBBoxRecord::drawTextOnPath(const void* text, size_t byteLength,
188                                  const SkPath& path, const SkMatrix* matrix,
189                                  const SkPaint& paint) {
190    SkRect bbox = path.getBounds();
191    SkPaint::FontMetrics metrics;
192    paint.getFontMetrics(&metrics);
193
194    // pad out all sides by the max glyph height above baseline
195    SkScalar pad = metrics.fTop;
196    bbox.fLeft += pad;
197    bbox.fRight -= pad;
198    bbox.fTop += pad;
199    bbox.fBottom -= pad;
200
201    if (this->transformBounds(bbox, &paint)) {
202        INHERITED::drawTextOnPath(text, byteLength, path, matrix, paint);
203    }
204}
205
206void SkBBoxRecord::drawVertices(VertexMode mode, int vertexCount,
207                                const SkPoint vertices[], const SkPoint texs[],
208                                const SkColor colors[], SkXfermode* xfer,
209                                const uint16_t indices[], int indexCount,
210                                const SkPaint& paint) {
211    SkRect bbox;
212    bbox.set(vertices, vertexCount);
213    if (this->transformBounds(bbox, &paint)) {
214        INHERITED::drawVertices(mode, vertexCount, vertices, texs,
215                                colors, xfer, indices, indexCount, paint);
216    }
217}
218
219void SkBBoxRecord::drawPicture(SkPicture& picture) {
220    SkRect bbox = {0, 0, picture.width(), picture.height()};
221    if (this->transformBounds(bbox, NULL)) {
222        INHERITED::drawPicture(picture);
223    }
224}
225
226bool SkBBoxRecord::transformBounds(const SkRect& bounds, const SkPaint* paint) {
227    SkRect outBounds = bounds;
228
229    if (paint) {
230        // account for stroking, path effects, shadows, etc
231        if (paint->canComputeFastBounds()) {
232            SkRect temp;
233            outBounds = paint->computeFastBounds(bounds, &temp);
234        } else {
235            // set bounds to current clip
236            if (!this->getClipBounds(&outBounds)) {
237                // current clip is empty
238                return false;
239            }
240        }
241    }
242
243    SkRect clip;
244
245    if (this->getClipBounds(&clip) && outBounds.intersect(clip)) {
246        this->getTotalMatrix().mapRect(&outBounds);
247        this->handleBBox(outBounds);
248        return true;
249    }
250
251    return false;
252}
253
254