gfx/2d/PathCairo.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "PathCairo.h"
     7 #include <math.h>
     8 #include "DrawTargetCairo.h"
     9 #include "Logging.h"
    10 #include "PathHelpers.h"
    11 #include "HelpersCairo.h"
    13 namespace mozilla {
    14 namespace gfx {
    16 PathBuilderCairo::PathBuilderCairo(FillRule aFillRule)
    17   : mFillRule(aFillRule)
    18 {
    19 }
    21 void
    22 PathBuilderCairo::MoveTo(const Point &aPoint)
    23 {
    24   cairo_path_data_t data;
    25   data.header.type = CAIRO_PATH_MOVE_TO;
    26   data.header.length = 2;
    27   mPathData.push_back(data);
    28   data.point.x = aPoint.x;
    29   data.point.y = aPoint.y;
    30   mPathData.push_back(data);
    32   mBeginPoint = mCurrentPoint = aPoint;
    33 }
    35 void
    36 PathBuilderCairo::LineTo(const Point &aPoint)
    37 {
    38   cairo_path_data_t data;
    39   data.header.type = CAIRO_PATH_LINE_TO;
    40   data.header.length = 2;
    41   mPathData.push_back(data);
    42   data.point.x = aPoint.x;
    43   data.point.y = aPoint.y;
    44   mPathData.push_back(data);
    46   mCurrentPoint = aPoint;
    47 }
    49 void
    50 PathBuilderCairo::BezierTo(const Point &aCP1,
    51                            const Point &aCP2,
    52                            const Point &aCP3)
    53 {
    54   cairo_path_data_t data;
    55   data.header.type = CAIRO_PATH_CURVE_TO;
    56   data.header.length = 4;
    57   mPathData.push_back(data);
    58   data.point.x = aCP1.x;
    59   data.point.y = aCP1.y;
    60   mPathData.push_back(data);
    61   data.point.x = aCP2.x;
    62   data.point.y = aCP2.y;
    63   mPathData.push_back(data);
    64   data.point.x = aCP3.x;
    65   data.point.y = aCP3.y;
    66   mPathData.push_back(data);
    68   mCurrentPoint = aCP3;
    69 }
    71 void
    72 PathBuilderCairo::QuadraticBezierTo(const Point &aCP1,
    73                                     const Point &aCP2)
    74 {
    75   // We need to elevate the degree of this quadratic Bézier to cubic, so we're
    76   // going to add an intermediate control point, and recompute control point 1.
    77   // The first and last control points remain the same.
    78   // This formula can be found on http://fontforge.sourceforge.net/bezier.html
    79   Point CP0 = CurrentPoint();
    80   Point CP1 = (CP0 + aCP1 * 2.0) / 3.0;
    81   Point CP2 = (aCP2 + aCP1 * 2.0) / 3.0;
    82   Point CP3 = aCP2;
    84   cairo_path_data_t data;
    85   data.header.type = CAIRO_PATH_CURVE_TO;
    86   data.header.length = 4;
    87   mPathData.push_back(data);
    88   data.point.x = CP1.x;
    89   data.point.y = CP1.y;
    90   mPathData.push_back(data);
    91   data.point.x = CP2.x;
    92   data.point.y = CP2.y;
    93   mPathData.push_back(data);
    94   data.point.x = CP3.x;
    95   data.point.y = CP3.y;
    96   mPathData.push_back(data);
    98   mCurrentPoint = aCP2;
    99 }
   101 void
   102 PathBuilderCairo::Close()
   103 {
   104   cairo_path_data_t data;
   105   data.header.type = CAIRO_PATH_CLOSE_PATH;
   106   data.header.length = 1;
   107   mPathData.push_back(data);
   109   mCurrentPoint = mBeginPoint;
   110 }
   112 void
   113 PathBuilderCairo::Arc(const Point &aOrigin, float aRadius, float aStartAngle,
   114                      float aEndAngle, bool aAntiClockwise)
   115 {
   116   ArcToBezier(this, aOrigin, Size(aRadius, aRadius), aStartAngle, aEndAngle, aAntiClockwise);
   117 }
   119 Point
   120 PathBuilderCairo::CurrentPoint() const
   121 {
   122   return mCurrentPoint;
   123 }
   125 TemporaryRef<Path>
   126 PathBuilderCairo::Finish()
   127 {
   128   return new PathCairo(mFillRule, mPathData, mCurrentPoint);
   129 }
   131 PathCairo::PathCairo(FillRule aFillRule, std::vector<cairo_path_data_t> &aPathData, const Point &aCurrentPoint)
   132   : mFillRule(aFillRule)
   133   , mContainingContext(nullptr)
   134   , mCurrentPoint(aCurrentPoint)
   135 {
   136   mPathData.swap(aPathData);
   137 }
   139 PathCairo::PathCairo(cairo_t *aContext)
   140   : mFillRule(FillRule::FILL_WINDING)
   141   , mContainingContext(nullptr)
   142 {
   143   cairo_path_t *path = cairo_copy_path(aContext);
   145   // XXX - mCurrentPoint is not properly set here, the same is true for the
   146   // D2D Path code, we never require current point when hitting this codepath
   147   // but this should be fixed.
   148   for (int i = 0; i < path->num_data; i++) {
   149     mPathData.push_back(path->data[i]);
   150   }
   152   cairo_path_destroy(path);
   153 }
   155 PathCairo::~PathCairo()
   156 {
   157   if (mContainingContext) {
   158     cairo_destroy(mContainingContext);
   159   }
   160 }
   162 TemporaryRef<PathBuilder>
   163 PathCairo::CopyToBuilder(FillRule aFillRule) const
   164 {
   165   RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(aFillRule);
   167   builder->mPathData = mPathData;
   168   builder->mCurrentPoint = mCurrentPoint;
   170   return builder;
   171 }
   173 TemporaryRef<PathBuilder>
   174 PathCairo::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const
   175 {
   176   RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(aFillRule);
   178   AppendPathToBuilder(builder, &aTransform);
   179   builder->mCurrentPoint = aTransform * mCurrentPoint;
   181   return builder;
   182 }
   184 bool
   185 PathCairo::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
   186 {
   187   Matrix inverse = aTransform;
   188   inverse.Invert();
   189   Point transformed = inverse * aPoint;
   191   EnsureContainingContext();
   193   return cairo_in_fill(mContainingContext, transformed.x, transformed.y);
   194 }
   196 bool
   197 PathCairo::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
   198                                const Point &aPoint,
   199                                const Matrix &aTransform) const
   200 {
   201   Matrix inverse = aTransform;
   202   inverse.Invert();
   203   Point transformed = inverse * aPoint;
   205   EnsureContainingContext();
   207   SetCairoStrokeOptions(mContainingContext, aStrokeOptions);
   209   return cairo_in_stroke(mContainingContext, transformed.x, transformed.y);
   210 }
   212 Rect
   213 PathCairo::GetBounds(const Matrix &aTransform) const
   214 {
   215   EnsureContainingContext();
   217   double x1, y1, x2, y2;
   219   cairo_path_extents(mContainingContext, &x1, &y1, &x2, &y2);
   220   Rect bounds(Float(x1), Float(y1), Float(x2 - x1), Float(y2 - y1));
   221   return aTransform.TransformBounds(bounds);
   222 }
   224 Rect
   225 PathCairo::GetStrokedBounds(const StrokeOptions &aStrokeOptions,
   226                             const Matrix &aTransform) const
   227 {
   228   EnsureContainingContext();
   230   double x1, y1, x2, y2;
   232   SetCairoStrokeOptions(mContainingContext, aStrokeOptions);
   234   cairo_stroke_extents(mContainingContext, &x1, &y1, &x2, &y2);
   235   Rect bounds((Float)x1, (Float)y1, (Float)(x2 - x1), (Float)(y2 - y1));
   236   return aTransform.TransformBounds(bounds);
   237 }
   239 void
   240 PathCairo::StreamToSink(PathSink *aSink) const
   241 {
   242   for (size_t i = 0; i < mPathData.size(); i++) {
   243     switch (mPathData[i].header.type) {
   244     case CAIRO_PATH_MOVE_TO:
   245       i++;
   246       aSink->MoveTo(Point(mPathData[i].point.x, mPathData[i].point.y));
   247       break;
   248     case CAIRO_PATH_LINE_TO:
   249       i++;
   250       aSink->LineTo(Point(mPathData[i].point.x, mPathData[i].point.y));
   251       break;
   252     case CAIRO_PATH_CURVE_TO:
   253       aSink->BezierTo(Point(mPathData[i + 1].point.x, mPathData[i + 1].point.y),
   254                       Point(mPathData[i + 2].point.x, mPathData[i + 2].point.y),
   255                       Point(mPathData[i + 3].point.x, mPathData[i + 3].point.y));
   256       i += 3;
   257       break;
   258     case CAIRO_PATH_CLOSE_PATH:
   259       aSink->Close();
   260       break;
   261     default:
   262       // Corrupt path data!
   263       MOZ_ASSERT(false);
   264     }
   265   }
   266 }
   268 void
   269 PathCairo::EnsureContainingContext() const
   270 {
   271   if (mContainingContext) {
   272     return;
   273   }
   275   mContainingContext = cairo_create(DrawTargetCairo::GetDummySurface());
   277   SetPathOnContext(mContainingContext);
   278 }
   280 void
   281 PathCairo::SetPathOnContext(cairo_t *aContext) const
   282 {
   283   // Needs the correct fill rule set.
   284   cairo_set_fill_rule(aContext, GfxFillRuleToCairoFillRule(mFillRule));
   286   cairo_new_path(aContext);
   288   if (mPathData.size()) {
   289     cairo_path_t path;
   290     path.data = const_cast<cairo_path_data_t*>(&mPathData.front());
   291     path.num_data = mPathData.size();
   292     path.status = CAIRO_STATUS_SUCCESS;
   293     cairo_append_path(aContext, &path);
   294   }
   295 }
   297 void
   298 PathCairo::AppendPathToBuilder(PathBuilderCairo *aBuilder, const Matrix *aTransform) const
   299 {
   300   if (aTransform) {
   301     size_t i = 0;
   302     while (i < mPathData.size()) {
   303       uint32_t pointCount = mPathData[i].header.length - 1;
   304       aBuilder->mPathData.push_back(mPathData[i]);
   305       i++;
   306       for (uint32_t c = 0; c < pointCount; c++) {
   307         cairo_path_data_t data;
   308         Point newPoint = *aTransform * Point(mPathData[i].point.x, mPathData[i].point.y);
   309         data.point.x = newPoint.x;
   310         data.point.y = newPoint.y;
   311         aBuilder->mPathData.push_back(data);
   312         i++;
   313       }
   314     }
   315   } else {
   316     for (size_t i = 0; i < mPathData.size(); i++) {
   317       aBuilder->mPathData.push_back(mPathData[i]);
   318     }
   319   }
   320 }
   322 }
   323 }

mercurial