1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2012 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTypes.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if defined(SK_BUILD_FOR_WIN)
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkDWriteGeometrySink.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkFloatUtils.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPath.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <dwrite.h>
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <d2d1.h>
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkDWriteGeometrySink::SkDWriteGeometrySink(SkPath* path) : fRefCount(1), fPath(path) { }
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkDWriteGeometrySink::~SkDWriteGeometrySink() { }
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotHRESULT STDMETHODCALLTYPE SkDWriteGeometrySink::QueryInterface(REFIID iid, void **object) {
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (nullptr == object) {
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return E_INVALIDARG;
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (iid == __uuidof(IUnknown) || iid == __uuidof(IDWriteGeometrySink)) {
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        *object = static_cast<IDWriteGeometrySink*>(this);
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->AddRef();
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return S_OK;
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        *object = nullptr;
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return E_NOINTERFACE;
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotULONG STDMETHODCALLTYPE SkDWriteGeometrySink::AddRef(void) {
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return static_cast<ULONG>(InterlockedIncrement(&fRefCount));
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotULONG STDMETHODCALLTYPE SkDWriteGeometrySink::Release(void) {
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ULONG res = static_cast<ULONG>(InterlockedDecrement(&fRefCount));
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (0 == res) {
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        delete this;
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return res;
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid STDMETHODCALLTYPE SkDWriteGeometrySink::SetFillMode(D2D1_FILL_MODE fillMode) {
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch (fillMode) {
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    case D2D1_FILL_MODE_ALTERNATE:
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fPath->setFillType(SkPath::kEvenOdd_FillType);
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        break;
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    case D2D1_FILL_MODE_WINDING:
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fPath->setFillType(SkPath::kWinding_FillType);
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        break;
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    default:
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDEBUGFAIL("Unknown D2D1_FILL_MODE.");
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        break;
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid STDMETHODCALLTYPE SkDWriteGeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT vertexFlags) {
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (vertexFlags == D2D1_PATH_SEGMENT_NONE || vertexFlags == D2D1_PATH_SEGMENT_FORCE_ROUND_LINE_JOIN) {
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDEBUGFAIL("Invalid D2D1_PATH_SEGMENT value.");
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid STDMETHODCALLTYPE SkDWriteGeometrySink::BeginFigure(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin) {
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fPath->moveTo(startPoint.x, startPoint.y);
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (figureBegin == D2D1_FIGURE_BEGIN_HOLLOW) {
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDEBUGFAIL("Invalid D2D1_FIGURE_BEGIN value.");
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid STDMETHODCALLTYPE SkDWriteGeometrySink::AddLines(const D2D1_POINT_2F *points, UINT pointsCount) {
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (const D2D1_POINT_2F *end = &points[pointsCount]; points < end; ++points) {
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fPath->lineTo(points->x, points->y);
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic bool approximately_equal(float a, float b) {
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkFloatingPoint<float, 10> lhs(a), rhs(b);
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return lhs.AlmostEquals(rhs);
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottypedef struct {
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    float x;
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    float y;
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} Cubic[4], Quadratic[3];
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic bool check_quadratic(const Cubic& cubic, Quadratic& reduction) {
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    float dx10 = cubic[1].x - cubic[0].x;
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    float dx23 = cubic[2].x - cubic[3].x;
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    float midX = cubic[0].x + dx10 * 3 / 2;
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    //NOTE: !approximately_equal(midX - cubic[3].x, dx23 * 3 / 2)
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    //does not work as subnormals get in between the left side and 0.
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!approximately_equal(midX, (dx23 * 3 / 2) + cubic[3].x)) {
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    float dy10 = cubic[1].y - cubic[0].y;
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    float dy23 = cubic[2].y - cubic[3].y;
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    float midY = cubic[0].y + dy10 * 3 / 2;
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!approximately_equal(midY, (dy23 * 3 / 2) + cubic[3].y)) {
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    reduction[0] = cubic[0];
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    reduction[1].x = midX;
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    reduction[1].y = midY;
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    reduction[2] = cubic[3];
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return true;
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid STDMETHODCALLTYPE SkDWriteGeometrySink::AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, UINT beziersCount) {
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPoint lastPt;
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fPath->getLastPt(&lastPt);
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    D2D1_POINT_2F prevPt = { SkScalarToFloat(lastPt.fX), SkScalarToFloat(lastPt.fY) };
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (const D2D1_BEZIER_SEGMENT *end = &beziers[beziersCount]; beziers < end; ++beziers) {
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        Cubic cubic = { { prevPt.x, prevPt.y },
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        { beziers->point1.x, beziers->point1.y },
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        { beziers->point2.x, beziers->point2.y },
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        { beziers->point3.x, beziers->point3.y }, };
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        Quadratic quadratic;
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (check_quadratic(cubic, quadratic)) {
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fPath->quadTo(quadratic[1].x, quadratic[1].y,
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                          quadratic[2].x, quadratic[2].y);
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fPath->cubicTo(beziers->point1.x, beziers->point1.y,
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                           beziers->point2.x, beziers->point2.y,
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                           beziers->point3.x, beziers->point3.y);
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        prevPt = beziers->point3;
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid STDMETHODCALLTYPE SkDWriteGeometrySink::EndFigure(D2D1_FIGURE_END figureEnd) {
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fPath->close();
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotHRESULT SkDWriteGeometrySink::Close() {
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return S_OK;
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotHRESULT SkDWriteGeometrySink::Create(SkPath* path, IDWriteGeometrySink** geometryToPath) {
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    *geometryToPath = new SkDWriteGeometrySink(path);
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return S_OK;
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif//defined(SK_BUILD_FOR_WIN)
150