gfx/skia/trunk/src/core/SkBBoxRecord.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/core/SkBBoxRecord.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,302 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2012 Google Inc.
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +#include "SkBBoxRecord.h"
    1.13 +
    1.14 +void SkBBoxRecord::drawOval(const SkRect& rect, const SkPaint& paint) {
    1.15 +    if (this->transformBounds(rect, &paint)) {
    1.16 +        INHERITED::drawOval(rect, paint);
    1.17 +    }
    1.18 +}
    1.19 +
    1.20 +void SkBBoxRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
    1.21 +    if (this->transformBounds(rrect.rect(), &paint)) {
    1.22 +        INHERITED::drawRRect(rrect, paint);
    1.23 +    }
    1.24 +}
    1.25 +
    1.26 +void SkBBoxRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
    1.27 +    if (this->transformBounds(rect, &paint)) {
    1.28 +        INHERITED::drawRect(rect, paint);
    1.29 +    }
    1.30 +}
    1.31 +
    1.32 +void SkBBoxRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
    1.33 +                                const SkPaint& paint) {
    1.34 +    if (this->transformBounds(outer.rect(), &paint)) {
    1.35 +        this->INHERITED::onDrawDRRect(outer, inner, paint);
    1.36 +    }
    1.37 +}
    1.38 +
    1.39 +void SkBBoxRecord::drawPath(const SkPath& path, const SkPaint& paint) {
    1.40 +    if (path.isInverseFillType()) {
    1.41 +        // If path is inverse filled, use the current clip bounds as the
    1.42 +        // path's device-space bounding box.
    1.43 +        SkIRect clipBounds;
    1.44 +        if (this->getClipDeviceBounds(&clipBounds)) {
    1.45 +            this->handleBBox(SkRect::Make(clipBounds));
    1.46 +            INHERITED::drawPath(path, paint);
    1.47 +        }
    1.48 +    } else if (this->transformBounds(path.getBounds(), &paint)) {
    1.49 +        INHERITED::drawPath(path, paint);
    1.50 +    }
    1.51 +}
    1.52 +
    1.53 +void SkBBoxRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
    1.54 +                              const SkPaint& paint) {
    1.55 +    SkRect bbox;
    1.56 +    bbox.set(pts, SkToInt(count));
    1.57 +    // Small min width value, just to ensure hairline point bounding boxes aren't empty.
    1.58 +    // Even though we know hairline primitives are drawn one pixel wide, we do not use a
    1.59 +    // minimum of 1 because the playback scale factor is unknown at record time. Later
    1.60 +    // outsets will take care of adding additional padding for antialiasing and rounding out
    1.61 +    // to integer device coordinates, guaranteeing that the rasterized pixels will be included
    1.62 +    // in the computed bounds.
    1.63 +    // Note: The device coordinate outset in SkBBoxHierarchyRecord::handleBBox is currently
    1.64 +    // done in the recording coordinate space, which is wrong.
    1.65 +    // http://code.google.com/p/skia/issues/detail?id=1021
    1.66 +    static const SkScalar kMinWidth = 0.01f;
    1.67 +    SkScalar halfStrokeWidth = SkMaxScalar(paint.getStrokeWidth(), kMinWidth) / 2;
    1.68 +    bbox.outset(halfStrokeWidth, halfStrokeWidth);
    1.69 +    if (this->transformBounds(bbox, &paint)) {
    1.70 +        INHERITED::drawPoints(mode, count, pts, paint);
    1.71 +    }
    1.72 +}
    1.73 +
    1.74 +void SkBBoxRecord::drawPaint(const SkPaint& paint) {
    1.75 +    SkRect bbox;
    1.76 +    if (this->getClipBounds(&bbox)) {
    1.77 +        if (this->transformBounds(bbox, &paint)) {
    1.78 +            INHERITED::drawPaint(paint);
    1.79 +        }
    1.80 +    }
    1.81 +}
    1.82 +
    1.83 +void SkBBoxRecord::clear(SkColor color) {
    1.84 +    SkISize size = this->getDeviceSize();
    1.85 +    SkRect bbox = {0, 0, SkIntToScalar(size.width()), SkIntToScalar(size.height())};
    1.86 +    this->handleBBox(bbox);
    1.87 +    INHERITED::clear(color);
    1.88 +}
    1.89 +
    1.90 +void SkBBoxRecord::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
    1.91 +                            const SkPaint& paint) {
    1.92 +    SkRect bbox;
    1.93 +    paint.measureText(text, byteLength, &bbox);
    1.94 +    SkPaint::FontMetrics metrics;
    1.95 +    paint.getFontMetrics(&metrics);
    1.96 +
    1.97 +    // Vertical and aligned text need to be offset
    1.98 +    if (paint.isVerticalText()) {
    1.99 +        SkScalar h = bbox.fBottom - bbox.fTop;
   1.100 +        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
   1.101 +            bbox.fTop    -= h / 2;
   1.102 +            bbox.fBottom -= h / 2;
   1.103 +        }
   1.104 +        // Pad top and bottom with max extents from FontMetrics
   1.105 +        bbox.fBottom += metrics.fBottom;
   1.106 +        bbox.fTop += metrics.fTop;
   1.107 +    } else {
   1.108 +        SkScalar w = bbox.fRight - bbox.fLeft;
   1.109 +        if (paint.getTextAlign() == SkPaint::kCenter_Align) {
   1.110 +            bbox.fLeft  -= w / 2;
   1.111 +            bbox.fRight -= w / 2;
   1.112 +        } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
   1.113 +            bbox.fLeft  -= w;
   1.114 +            bbox.fRight -= w;
   1.115 +        }
   1.116 +        // Set vertical bounds to max extents from font metrics
   1.117 +        bbox.fTop = metrics.fTop;
   1.118 +        bbox.fBottom = metrics.fBottom;
   1.119 +    }
   1.120 +
   1.121 +    // Pad horizontal bounds on each side by half of max vertical extents (this is sort of
   1.122 +    // arbitrary, but seems to produce reasonable results, if there were a way of getting max
   1.123 +    // glyph X-extents to pad by, that may be better here, but FontMetrics fXMin and fXMax seem
   1.124 +    // incorrect on most platforms (too small in Linux, never even set in Windows).
   1.125 +    SkScalar pad = (metrics.fBottom - metrics.fTop) / 2;
   1.126 +    bbox.fLeft  -= pad;
   1.127 +    bbox.fRight += pad;
   1.128 +
   1.129 +    bbox.fLeft += x;
   1.130 +    bbox.fRight += x;
   1.131 +    bbox.fTop += y;
   1.132 +    bbox.fBottom += y;
   1.133 +    if (this->transformBounds(bbox, &paint)) {
   1.134 +        INHERITED::drawText(text, byteLength, x, y, paint);
   1.135 +    }
   1.136 +}
   1.137 +
   1.138 +void SkBBoxRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
   1.139 +                              const SkPaint* paint) {
   1.140 +    SkRect bbox = {left, top, left + bitmap.width(), top + bitmap.height()};
   1.141 +    if (this->transformBounds(bbox, paint)) {
   1.142 +        INHERITED::drawBitmap(bitmap, left, top, paint);
   1.143 +    }
   1.144 +}
   1.145 +
   1.146 +void SkBBoxRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
   1.147 +                                        const SkRect& dst, const SkPaint* paint,
   1.148 +                                        DrawBitmapRectFlags flags) {
   1.149 +    if (this->transformBounds(dst, paint)) {
   1.150 +        INHERITED::drawBitmapRectToRect(bitmap, src, dst, paint, flags);
   1.151 +    }
   1.152 +}
   1.153 +
   1.154 +void SkBBoxRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& mat,
   1.155 +                                    const SkPaint* paint) {
   1.156 +    SkMatrix m = mat;
   1.157 +    SkRect bbox = {0, 0, SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())};
   1.158 +    m.mapRect(&bbox);
   1.159 +    if (this->transformBounds(bbox, paint)) {
   1.160 +        INHERITED::drawBitmapMatrix(bitmap, mat, paint);
   1.161 +    }
   1.162 +}
   1.163 +
   1.164 +void SkBBoxRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
   1.165 +                                  const SkRect& dst, const SkPaint* paint) {
   1.166 +    if (this->transformBounds(dst, paint)) {
   1.167 +        INHERITED::drawBitmapNine(bitmap, center, dst, paint);
   1.168 +    }
   1.169 +}
   1.170 +
   1.171 +void SkBBoxRecord::drawPosText(const void* text, size_t byteLength,
   1.172 +                               const SkPoint pos[], const SkPaint& paint) {
   1.173 +    SkRect bbox;
   1.174 +    bbox.set(pos, paint.countText(text, byteLength));
   1.175 +    SkPaint::FontMetrics metrics;
   1.176 +    paint.getFontMetrics(&metrics);
   1.177 +    bbox.fTop += metrics.fTop;
   1.178 +    bbox.fBottom += metrics.fBottom;
   1.179 +
   1.180 +    // pad on left and right by half of max vertical glyph extents
   1.181 +    SkScalar pad = (metrics.fTop - metrics.fBottom) / 2;
   1.182 +    bbox.fLeft += pad;
   1.183 +    bbox.fRight -= pad;
   1.184 +
   1.185 +    if (this->transformBounds(bbox, &paint)) {
   1.186 +        INHERITED::drawPosText(text, byteLength, pos, paint);
   1.187 +    }
   1.188 +}
   1.189 +
   1.190 +void SkBBoxRecord::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
   1.191 +                                SkScalar constY, const SkPaint& paint) {
   1.192 +    size_t numChars = paint.countText(text, byteLength);
   1.193 +    if (numChars == 0) {
   1.194 +        return;
   1.195 +    }
   1.196 +
   1.197 +    const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
   1.198 +    WriteTopBot(paint, *flatPaintData);
   1.199 +
   1.200 +    SkScalar top = flatPaintData->topBot()[0];
   1.201 +    SkScalar bottom = flatPaintData->topBot()[1];
   1.202 +    SkScalar pad = top - bottom;
   1.203 +
   1.204 +    SkRect bbox;
   1.205 +    bbox.fLeft = SK_ScalarMax;
   1.206 +    bbox.fRight = SK_ScalarMin;
   1.207 +
   1.208 +    for (size_t i = 0; i < numChars; ++i) {
   1.209 +        if (xpos[i] < bbox.fLeft) {
   1.210 +            bbox.fLeft = xpos[i];
   1.211 +        }
   1.212 +        if (xpos[i] > bbox.fRight) {
   1.213 +            bbox.fRight = xpos[i];
   1.214 +        }
   1.215 +    }
   1.216 +
   1.217 +    // pad horizontally by max glyph height
   1.218 +    bbox.fLeft  += pad;
   1.219 +    bbox.fRight -= pad;
   1.220 +
   1.221 +    bbox.fTop    = top + constY;
   1.222 +    bbox.fBottom = bottom + constY;
   1.223 +
   1.224 +    if (!this->transformBounds(bbox, &paint)) {
   1.225 +        return;
   1.226 +    }
   1.227 +    // This is the equivalent of calling:
   1.228 +    //  INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint);
   1.229 +    // but we filled our flat paint beforehand so that we could get font metrics.
   1.230 +    drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
   1.231 +}
   1.232 +
   1.233 +void SkBBoxRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
   1.234 +                              const SkPaint* paint) {
   1.235 +    SkRect bbox;
   1.236 +    bbox.set(SkIRect::MakeXYWH(left, top, bitmap.width(), bitmap.height()));
   1.237 +    this->handleBBox(bbox); // directly call handleBBox, matrix is ignored
   1.238 +    INHERITED::drawSprite(bitmap, left, top, paint);
   1.239 +}
   1.240 +
   1.241 +void SkBBoxRecord::drawTextOnPath(const void* text, size_t byteLength,
   1.242 +                                  const SkPath& path, const SkMatrix* matrix,
   1.243 +                                  const SkPaint& paint) {
   1.244 +    SkRect bbox = path.getBounds();
   1.245 +    SkPaint::FontMetrics metrics;
   1.246 +    paint.getFontMetrics(&metrics);
   1.247 +
   1.248 +    // pad out all sides by the max glyph height above baseline
   1.249 +    SkScalar pad = metrics.fTop;
   1.250 +    bbox.fLeft += pad;
   1.251 +    bbox.fRight -= pad;
   1.252 +    bbox.fTop += pad;
   1.253 +    bbox.fBottom -= pad;
   1.254 +
   1.255 +    if (this->transformBounds(bbox, &paint)) {
   1.256 +        INHERITED::drawTextOnPath(text, byteLength, path, matrix, paint);
   1.257 +    }
   1.258 +}
   1.259 +
   1.260 +void SkBBoxRecord::drawVertices(VertexMode mode, int vertexCount,
   1.261 +                                const SkPoint vertices[], const SkPoint texs[],
   1.262 +                                const SkColor colors[], SkXfermode* xfer,
   1.263 +                                const uint16_t indices[], int indexCount,
   1.264 +                                const SkPaint& paint) {
   1.265 +    SkRect bbox;
   1.266 +    bbox.set(vertices, vertexCount);
   1.267 +    if (this->transformBounds(bbox, &paint)) {
   1.268 +        INHERITED::drawVertices(mode, vertexCount, vertices, texs,
   1.269 +                                colors, xfer, indices, indexCount, paint);
   1.270 +    }
   1.271 +}
   1.272 +
   1.273 +void SkBBoxRecord::drawPicture(SkPicture& picture) {
   1.274 +    if (picture.width() > 0 && picture.height() > 0 &&
   1.275 +        this->transformBounds(SkRect::MakeWH(picture.width(), picture.height()), NULL)) {
   1.276 +        INHERITED::drawPicture(picture);
   1.277 +    }
   1.278 +}
   1.279 +
   1.280 +bool SkBBoxRecord::transformBounds(const SkRect& bounds, const SkPaint* paint) {
   1.281 +    SkRect outBounds = bounds;
   1.282 +    outBounds.sort();
   1.283 +
   1.284 +    if (paint) {
   1.285 +        // account for stroking, path effects, shadows, etc
   1.286 +        if (paint->canComputeFastBounds()) {
   1.287 +            SkRect temp;
   1.288 +            outBounds = paint->computeFastBounds(outBounds, &temp);
   1.289 +        } else {
   1.290 +            // set bounds to current clip
   1.291 +            if (!this->getClipBounds(&outBounds)) {
   1.292 +                // current clip is empty
   1.293 +                return false;
   1.294 +            }
   1.295 +        }
   1.296 +    }
   1.297 +
   1.298 +    if (!outBounds.isEmpty() && !this->quickReject(outBounds)) {
   1.299 +        this->getTotalMatrix().mapRect(&outBounds);
   1.300 +        this->handleBBox(outBounds);
   1.301 +        return true;
   1.302 +    }
   1.303 +
   1.304 +    return false;
   1.305 +}

mercurial