gfx/2d/PathCG.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 "PathCG.h"
     7 #include <math.h>
     8 #include "DrawTargetCG.h"
     9 #include "Logging.h"
    11 namespace mozilla {
    12 namespace gfx {
    14 PathBuilderCG::~PathBuilderCG()
    15 {
    16   CGPathRelease(mCGPath);
    17 }
    19 void
    20 PathBuilderCG::MoveTo(const Point &aPoint)
    21 {
    22   CGPathMoveToPoint(mCGPath, nullptr, aPoint.x, aPoint.y);
    23 }
    25 void
    26 PathBuilderCG::LineTo(const Point &aPoint)
    27 {
    28   if (CGPathIsEmpty(mCGPath))
    29     MoveTo(aPoint);
    30   else
    31     CGPathAddLineToPoint(mCGPath, nullptr, aPoint.x, aPoint.y);
    32 }
    34 void
    35 PathBuilderCG::BezierTo(const Point &aCP1,
    36                          const Point &aCP2,
    37                          const Point &aCP3)
    38 {
    40   if (CGPathIsEmpty(mCGPath))
    41     MoveTo(aCP1);
    42   CGPathAddCurveToPoint(mCGPath, nullptr,
    43                           aCP1.x, aCP1.y,
    44                           aCP2.x, aCP2.y,
    45                           aCP3.x, aCP3.y);
    47 }
    49 void
    50 PathBuilderCG::QuadraticBezierTo(const Point &aCP1,
    51                                   const Point &aCP2)
    52 {
    53   if (CGPathIsEmpty(mCGPath))
    54     MoveTo(aCP1);
    55   CGPathAddQuadCurveToPoint(mCGPath, nullptr,
    56                               aCP1.x, aCP1.y,
    57                               aCP2.x, aCP2.y);
    58 }
    60 void
    61 PathBuilderCG::Close()
    62 {
    63   if (!CGPathIsEmpty(mCGPath))
    64     CGPathCloseSubpath(mCGPath);
    65 }
    67 void
    68 PathBuilderCG::Arc(const Point &aOrigin, Float aRadius, Float aStartAngle,
    69                  Float aEndAngle, bool aAntiClockwise)
    70 {
    71   // Core Graphic's initial coordinate system is y-axis up, whereas Moz2D's is
    72   // y-axis down. Core Graphics therefore considers "clockwise" to mean "sweep
    73   // in the direction of decreasing angle" whereas Moz2D considers it to mean
    74   // "sweep in the direction of increasing angle". In other words if this
    75   // Moz2D method is instructed to sweep anti-clockwise we need to tell
    76   // CGPathAddArc to sweep clockwise, and vice versa. Hence why we pass the
    77   // value of aAntiClockwise directly to CGPathAddArc's "clockwise" bool
    78   // parameter.
    79   CGPathAddArc(mCGPath, nullptr,
    80                aOrigin.x, aOrigin.y,
    81                aRadius,
    82                aStartAngle,
    83                aEndAngle,
    84                aAntiClockwise);
    85 }
    87 Point
    88 PathBuilderCG::CurrentPoint() const
    89 {
    90   CGPoint pt = CGPathGetCurrentPoint(mCGPath);
    91   Point ret(pt.x, pt.y);
    92   return ret;
    93 }
    95 void
    96 PathBuilderCG::EnsureActive(const Point &aPoint)
    97 {
    98 }
   100 TemporaryRef<Path>
   101 PathBuilderCG::Finish()
   102 {
   103   RefPtr<PathCG> path = new PathCG(mCGPath, mFillRule);
   104   return path;
   105 }
   107 TemporaryRef<PathBuilder>
   108 PathCG::CopyToBuilder(FillRule aFillRule) const
   109 {
   110   CGMutablePathRef path = CGPathCreateMutableCopy(mPath);
   111   RefPtr<PathBuilderCG> builder = new PathBuilderCG(path, aFillRule);
   112   return builder;
   113 }
   117 TemporaryRef<PathBuilder>
   118 PathCG::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const
   119 {
   120   // 10.7 adds CGPathCreateMutableCopyByTransformingPath it might be faster than doing
   121   // this by hand
   123   struct TransformApplier {
   124     CGMutablePathRef path;
   125     CGAffineTransform transform;
   126     static void
   127     TranformCGPathApplierFunc(void *vinfo, const CGPathElement *element)
   128     {
   129       TransformApplier *info = reinterpret_cast<TransformApplier*>(vinfo);
   130       switch (element->type) {
   131         case kCGPathElementMoveToPoint:
   132           {
   133             CGPoint pt = element->points[0];
   134             CGPathMoveToPoint(info->path, &info->transform, pt.x, pt.y);
   135             break;
   136           }
   137         case kCGPathElementAddLineToPoint:
   138           {
   139             CGPoint pt = element->points[0];
   140             CGPathAddLineToPoint(info->path, &info->transform, pt.x, pt.y);
   141             break;
   142           }
   143         case kCGPathElementAddQuadCurveToPoint:
   144           {
   145             CGPoint cpt = element->points[0];
   146             CGPoint pt  = element->points[1];
   147             CGPathAddQuadCurveToPoint(info->path, &info->transform, cpt.x, cpt.y, pt.x, pt.y);
   148             break;
   149           }
   150         case kCGPathElementAddCurveToPoint:
   151           {
   152             CGPoint cpt1 = element->points[0];
   153             CGPoint cpt2 = element->points[1];
   154             CGPoint pt   = element->points[2];
   155             CGPathAddCurveToPoint(info->path, &info->transform, cpt1.x, cpt1.y, cpt2.x, cpt2.y, pt.x, pt.y);
   156             break;
   157           }
   158         case kCGPathElementCloseSubpath:
   159           {
   160             CGPathCloseSubpath(info->path);
   161             break;
   162           }
   163       }
   164     }
   165   };
   167   TransformApplier ta;
   168   ta.path = CGPathCreateMutable();
   169   ta.transform = GfxMatrixToCGAffineTransform(aTransform);
   171   CGPathApply(mPath, &ta, TransformApplier::TranformCGPathApplierFunc);
   172   RefPtr<PathBuilderCG> builder = new PathBuilderCG(ta.path, aFillRule);
   173   return builder;
   174 }
   176 static void
   177 StreamPathToSinkApplierFunc(void *vinfo, const CGPathElement *element)
   178 {
   179   PathSink *sink = reinterpret_cast<PathSink*>(vinfo);
   180   switch (element->type) {
   181     case kCGPathElementMoveToPoint:
   182       {
   183         CGPoint pt = element->points[0];
   184         sink->MoveTo(CGPointToPoint(pt));
   185         break;
   186       }
   187     case kCGPathElementAddLineToPoint:
   188       {
   189         CGPoint pt = element->points[0];
   190         sink->LineTo(CGPointToPoint(pt));
   191         break;
   192       }
   193     case kCGPathElementAddQuadCurveToPoint:
   194       {
   195         CGPoint cpt = element->points[0];
   196         CGPoint pt  = element->points[1];
   197         sink->QuadraticBezierTo(CGPointToPoint(cpt),
   198                                 CGPointToPoint(pt));
   199         break;
   200       }
   201     case kCGPathElementAddCurveToPoint:
   202       {
   203         CGPoint cpt1 = element->points[0];
   204         CGPoint cpt2 = element->points[1];
   205         CGPoint pt   = element->points[2];
   206         sink->BezierTo(CGPointToPoint(cpt1),
   207                        CGPointToPoint(cpt2),
   208                        CGPointToPoint(pt));
   209         break;
   210       }
   211     case kCGPathElementCloseSubpath:
   212       {
   213         sink->Close();
   214         break;
   215       }
   216   }
   217 }
   219 void
   220 PathCG::StreamToSink(PathSink *aSink) const
   221 {
   222   CGPathApply(mPath, aSink, StreamPathToSinkApplierFunc);
   223 }
   225 bool
   226 PathCG::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
   227 {
   228   Matrix inverse = aTransform;
   229   inverse.Invert();
   230   Point transformedPoint = inverse*aPoint;
   231   // We could probably drop the input transform and just transform the point at the caller?
   232   CGPoint point = {transformedPoint.x, transformedPoint.y};
   234   // The transform parameter of CGPathContainsPoint doesn't seem to work properly on OS X 10.5
   235   // so we transform aPoint ourselves.
   236   return CGPathContainsPoint(mPath, nullptr, point, mFillRule == FillRule::FILL_EVEN_ODD);
   237 }
   239 static size_t
   240 PutBytesNull(void *info, const void *buffer, size_t count)
   241 {
   242   return count;
   243 }
   245 /* The idea of a scratch context comes from WebKit */
   246 static CGContextRef
   247 CreateScratchContext()
   248 {
   249   CGDataConsumerCallbacks callbacks = {PutBytesNull, nullptr};
   250   CGDataConsumerRef consumer = CGDataConsumerCreate(nullptr, &callbacks);
   251   CGContextRef cg = CGPDFContextCreate(consumer, nullptr, nullptr);
   252   CGDataConsumerRelease(consumer);
   253   return cg;
   254 }
   256 static CGContextRef
   257 ScratchContext()
   258 {
   259   static CGContextRef cg = CreateScratchContext();
   260   return cg;
   261 }
   263 bool
   264 PathCG::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
   265                             const Point &aPoint,
   266                             const Matrix &aTransform) const
   267 {
   268   Matrix inverse = aTransform;
   269   inverse.Invert();
   270   Point transformedPoint = inverse*aPoint;
   271   // We could probably drop the input transform and just transform the point at the caller?
   272   CGPoint point = {transformedPoint.x, transformedPoint.y};
   274   CGContextRef cg = ScratchContext();
   276   CGContextSaveGState(cg);
   278   CGContextBeginPath(cg);
   279   CGContextAddPath(cg, mPath);
   281   SetStrokeOptions(cg, aStrokeOptions);
   283   CGContextReplacePathWithStrokedPath(cg);
   284   CGContextRestoreGState(cg);
   286   CGPathRef sPath = CGContextCopyPath(cg);
   287   bool inStroke = CGPathContainsPoint(sPath, nullptr, point, false);
   288   CGPathRelease(sPath);
   290   return inStroke;
   291 }
   293 //XXX: what should these functions return for an empty path?
   294 // currently they return CGRectNull {inf,inf, 0, 0}
   295 Rect
   296 PathCG::GetBounds(const Matrix &aTransform) const
   297 {
   298   //XXX: are these bounds tight enough
   299   Rect bounds = CGRectToRect(CGPathGetBoundingBox(mPath));
   301   //XXX: currently this returns the bounds of the transformed bounds
   302   // this is strictly looser than the bounds of the transformed path
   303   return aTransform.TransformBounds(bounds);
   304 }
   306 Rect
   307 PathCG::GetStrokedBounds(const StrokeOptions &aStrokeOptions,
   308                          const Matrix &aTransform) const
   309 {
   310   // 10.7 has CGPathCreateCopyByStrokingPath which we could use
   311   // instead of this scratch context business
   312   CGContextRef cg = ScratchContext();
   314   CGContextSaveGState(cg);
   316   CGContextBeginPath(cg);
   317   CGContextAddPath(cg, mPath);
   319   SetStrokeOptions(cg, aStrokeOptions);
   321   CGContextReplacePathWithStrokedPath(cg);
   322   Rect bounds = CGRectToRect(CGContextGetPathBoundingBox(cg));
   324   CGContextRestoreGState(cg);
   326   if (!bounds.IsFinite()) {
   327     return Rect();
   328   }
   330   return aTransform.TransformBounds(bounds);
   331 }
   334 }
   336 }

mercurial