gfx/skia/trunk/src/utils/win/SkDWriteGeometrySink.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/utils/win/SkDWriteGeometrySink.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,146 @@
     1.4 +/*
     1.5 + * Copyright 2012 Google Inc.
     1.6 + *
     1.7 + * Use of this source code is governed by a BSD-style license that can be
     1.8 + * found in the LICENSE file.
     1.9 + */
    1.10 +
    1.11 +#include "SkTypes.h"
    1.12 +
    1.13 +#include "SkDWriteGeometrySink.h"
    1.14 +#include "SkFloatUtils.h"
    1.15 +#include "SkPath.h"
    1.16 +
    1.17 +#include <dwrite.h>
    1.18 +#include <d2d1.h>
    1.19 +
    1.20 +SkDWriteGeometrySink::SkDWriteGeometrySink(SkPath* path) : fRefCount(1), fPath(path) { }
    1.21 +
    1.22 +SkDWriteGeometrySink::~SkDWriteGeometrySink() { }
    1.23 +
    1.24 +HRESULT STDMETHODCALLTYPE SkDWriteGeometrySink::QueryInterface(REFIID iid, void **object) {
    1.25 +    if (NULL == object) {
    1.26 +        return E_INVALIDARG;
    1.27 +    }
    1.28 +    if (iid == __uuidof(IUnknown) || iid == __uuidof(IDWriteGeometrySink)) {
    1.29 +        *object = static_cast<IDWriteGeometrySink*>(this);
    1.30 +        this->AddRef();
    1.31 +        return S_OK;
    1.32 +    } else {
    1.33 +        *object = NULL;
    1.34 +        return E_NOINTERFACE;
    1.35 +    }
    1.36 +}
    1.37 +
    1.38 +ULONG STDMETHODCALLTYPE SkDWriteGeometrySink::AddRef(void) {
    1.39 +    return static_cast<ULONG>(InterlockedIncrement(&fRefCount));
    1.40 +}
    1.41 +
    1.42 +ULONG STDMETHODCALLTYPE SkDWriteGeometrySink::Release(void) {
    1.43 +    ULONG res = static_cast<ULONG>(InterlockedDecrement(&fRefCount));
    1.44 +    if (0 == res) {
    1.45 +        delete this;
    1.46 +    }
    1.47 +    return res;
    1.48 +}
    1.49 +
    1.50 +void STDMETHODCALLTYPE SkDWriteGeometrySink::SetFillMode(D2D1_FILL_MODE fillMode) {
    1.51 +    switch (fillMode) {
    1.52 +    case D2D1_FILL_MODE_ALTERNATE:
    1.53 +        fPath->setFillType(SkPath::kEvenOdd_FillType);
    1.54 +        break;
    1.55 +    case D2D1_FILL_MODE_WINDING:
    1.56 +        fPath->setFillType(SkPath::kWinding_FillType);
    1.57 +        break;
    1.58 +    default:
    1.59 +        SkDEBUGFAIL("Unknown D2D1_FILL_MODE.");
    1.60 +        break;
    1.61 +    }
    1.62 +}
    1.63 +
    1.64 +void STDMETHODCALLTYPE SkDWriteGeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT vertexFlags) {
    1.65 +    if (vertexFlags == D2D1_PATH_SEGMENT_NONE || vertexFlags == D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN) {
    1.66 +        SkDEBUGFAIL("Invalid D2D1_PATH_SEGMENT value.");
    1.67 +    }
    1.68 +}
    1.69 +
    1.70 +void STDMETHODCALLTYPE SkDWriteGeometrySink::BeginFigure(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin) {
    1.71 +    fPath->moveTo(startPoint.x, startPoint.y);
    1.72 +    if (figureBegin == D2D1_FIGURE_BEGIN_HOLLOW) {
    1.73 +        SkDEBUGFAIL("Invalid D2D1_FIGURE_BEGIN value.");
    1.74 +    }
    1.75 +}
    1.76 +
    1.77 +void STDMETHODCALLTYPE SkDWriteGeometrySink::AddLines(const D2D1_POINT_2F *points, UINT pointsCount) {
    1.78 +    for (const D2D1_POINT_2F *end = &points[pointsCount]; points < end; ++points) {
    1.79 +        fPath->lineTo(points->x, points->y);
    1.80 +    }
    1.81 +}
    1.82 +
    1.83 +static bool approximately_equal(float a, float b) {
    1.84 +    const SkFloatingPoint<float, 10> lhs(a), rhs(b);
    1.85 +    return lhs.AlmostEquals(rhs);
    1.86 +}
    1.87 +
    1.88 +typedef struct {
    1.89 +    float x;
    1.90 +    float y;
    1.91 +} Cubic[4], Quadratic[3];
    1.92 +
    1.93 +static bool check_quadratic(const Cubic& cubic, Quadratic& reduction) {
    1.94 +    float dx10 = cubic[1].x - cubic[0].x;
    1.95 +    float dx23 = cubic[2].x - cubic[3].x;
    1.96 +    float midX = cubic[0].x + dx10 * 3 / 2;
    1.97 +    //NOTE: !approximately_equal(midX - cubic[3].x, dx23 * 3 / 2)
    1.98 +    //does not work as subnormals get in between the left side and 0.
    1.99 +    if (!approximately_equal(midX, (dx23 * 3 / 2) + cubic[3].x)) {
   1.100 +        return false;
   1.101 +    }
   1.102 +    float dy10 = cubic[1].y - cubic[0].y;
   1.103 +    float dy23 = cubic[2].y - cubic[3].y;
   1.104 +    float midY = cubic[0].y + dy10 * 3 / 2;
   1.105 +    if (!approximately_equal(midY, (dy23 * 3 / 2) + cubic[3].y)) {
   1.106 +        return false;
   1.107 +    }
   1.108 +    reduction[0] = cubic[0];
   1.109 +    reduction[1].x = midX;
   1.110 +    reduction[1].y = midY;
   1.111 +    reduction[2] = cubic[3];
   1.112 +    return true;
   1.113 +}
   1.114 +
   1.115 +void STDMETHODCALLTYPE SkDWriteGeometrySink::AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, UINT beziersCount) {
   1.116 +    SkPoint lastPt;
   1.117 +    fPath->getLastPt(&lastPt);
   1.118 +    D2D1_POINT_2F prevPt = { SkScalarToFloat(lastPt.fX), SkScalarToFloat(lastPt.fY) };
   1.119 +
   1.120 +    for (const D2D1_BEZIER_SEGMENT *end = &beziers[beziersCount]; beziers < end; ++beziers) {
   1.121 +        Cubic cubic = { { prevPt.x, prevPt.y },
   1.122 +                        { beziers->point1.x, beziers->point1.y },
   1.123 +                        { beziers->point2.x, beziers->point2.y },
   1.124 +                        { beziers->point3.x, beziers->point3.y }, };
   1.125 +        Quadratic quadratic;
   1.126 +        if (check_quadratic(cubic, quadratic)) {
   1.127 +            fPath->quadTo(quadratic[1].x, quadratic[1].y,
   1.128 +                          quadratic[2].x, quadratic[2].y);
   1.129 +        } else {
   1.130 +            fPath->cubicTo(beziers->point1.x, beziers->point1.y,
   1.131 +                           beziers->point2.x, beziers->point2.y,
   1.132 +                           beziers->point3.x, beziers->point3.y);
   1.133 +        }
   1.134 +        prevPt = beziers->point3;
   1.135 +    }
   1.136 +}
   1.137 +
   1.138 +void STDMETHODCALLTYPE SkDWriteGeometrySink::EndFigure(D2D1_FIGURE_END figureEnd) {
   1.139 +    fPath->close();
   1.140 +}
   1.141 +
   1.142 +HRESULT SkDWriteGeometrySink::Close() {
   1.143 +    return S_OK;
   1.144 +}
   1.145 +
   1.146 +HRESULT SkDWriteGeometrySink::Create(SkPath* path, IDWriteGeometrySink** geometryToPath) {
   1.147 +    *geometryToPath = new SkDWriteGeometrySink(path);
   1.148 +    return S_OK;
   1.149 +}

mercurial