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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial