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