LCOV - code coverage report
Current view: top level - gfx/2d - PathCairo.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 169 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 23 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       5             : 
       6             : #include "PathCairo.h"
       7             : #include <math.h>
       8             : #include "DrawTargetCairo.h"
       9             : #include "Logging.h"
      10             : #include "PathHelpers.h"
      11             : #include "HelpersCairo.h"
      12             : 
      13             : namespace mozilla {
      14             : namespace gfx {
      15             : 
      16           0 : PathBuilderCairo::PathBuilderCairo(FillRule aFillRule)
      17           0 :   : mFillRule(aFillRule)
      18             : {
      19           0 : }
      20             : 
      21             : void
      22           0 : PathBuilderCairo::MoveTo(const Point &aPoint)
      23             : {
      24             :   cairo_path_data_t data;
      25           0 :   data.header.type = CAIRO_PATH_MOVE_TO;
      26           0 :   data.header.length = 2;
      27           0 :   mPathData.push_back(data);
      28           0 :   data.point.x = aPoint.x;
      29           0 :   data.point.y = aPoint.y;
      30           0 :   mPathData.push_back(data);
      31             : 
      32           0 :   mBeginPoint = mCurrentPoint = aPoint;
      33           0 : }
      34             : 
      35             : void
      36           0 : PathBuilderCairo::LineTo(const Point &aPoint)
      37             : {
      38             :   cairo_path_data_t data;
      39           0 :   data.header.type = CAIRO_PATH_LINE_TO;
      40           0 :   data.header.length = 2;
      41           0 :   mPathData.push_back(data);
      42           0 :   data.point.x = aPoint.x;
      43           0 :   data.point.y = aPoint.y;
      44           0 :   mPathData.push_back(data);
      45             : 
      46           0 :   mCurrentPoint = aPoint;
      47           0 : }
      48             : 
      49             : void
      50           0 : PathBuilderCairo::BezierTo(const Point &aCP1,
      51             :                            const Point &aCP2,
      52             :                            const Point &aCP3)
      53             : {
      54             :   cairo_path_data_t data;
      55           0 :   data.header.type = CAIRO_PATH_CURVE_TO;
      56           0 :   data.header.length = 4;
      57           0 :   mPathData.push_back(data);
      58           0 :   data.point.x = aCP1.x;
      59           0 :   data.point.y = aCP1.y;
      60           0 :   mPathData.push_back(data);
      61           0 :   data.point.x = aCP2.x;
      62           0 :   data.point.y = aCP2.y;
      63           0 :   mPathData.push_back(data);
      64           0 :   data.point.x = aCP3.x;
      65           0 :   data.point.y = aCP3.y;
      66           0 :   mPathData.push_back(data);
      67             : 
      68           0 :   mCurrentPoint = aCP3;
      69           0 : }
      70             : 
      71             : void
      72           0 : 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           0 :   Point CP0 = CurrentPoint();
      80           0 :   Point CP1 = (CP0 + aCP1 * 2.0) / 3.0;
      81           0 :   Point CP2 = (aCP2 + aCP1 * 2.0) / 3.0;
      82           0 :   Point CP3 = aCP2;
      83             : 
      84             :   cairo_path_data_t data;
      85           0 :   data.header.type = CAIRO_PATH_CURVE_TO;
      86           0 :   data.header.length = 4;
      87           0 :   mPathData.push_back(data);
      88           0 :   data.point.x = CP1.x;
      89           0 :   data.point.y = CP1.y;
      90           0 :   mPathData.push_back(data);
      91           0 :   data.point.x = CP2.x;
      92           0 :   data.point.y = CP2.y;
      93           0 :   mPathData.push_back(data);
      94           0 :   data.point.x = CP3.x;
      95           0 :   data.point.y = CP3.y;
      96           0 :   mPathData.push_back(data);
      97             : 
      98           0 :   mCurrentPoint = aCP2;
      99           0 : }
     100             : 
     101             : void
     102           0 : PathBuilderCairo::Close()
     103             : {
     104             :   cairo_path_data_t data;
     105           0 :   data.header.type = CAIRO_PATH_CLOSE_PATH;
     106           0 :   data.header.length = 1;
     107           0 :   mPathData.push_back(data);
     108             : 
     109           0 :   mCurrentPoint = mBeginPoint;
     110           0 : }
     111             : 
     112             : void
     113           0 : PathBuilderCairo::Arc(const Point &aOrigin, float aRadius, float aStartAngle,
     114             :                      float aEndAngle, bool aAntiClockwise)
     115             : {
     116           0 :   ArcToBezier(this, aOrigin, Size(aRadius, aRadius), aStartAngle, aEndAngle, aAntiClockwise);
     117           0 : }
     118             : 
     119             : Point
     120           0 : PathBuilderCairo::CurrentPoint() const
     121             : {
     122           0 :   return mCurrentPoint;
     123             : }
     124             : 
     125             : already_AddRefed<Path>
     126           0 : PathBuilderCairo::Finish()
     127             : {
     128           0 :   return MakeAndAddRef<PathCairo>(mFillRule, mPathData, mCurrentPoint);
     129             : }
     130             : 
     131           0 : PathCairo::PathCairo(FillRule aFillRule, std::vector<cairo_path_data_t> &aPathData, const Point &aCurrentPoint)
     132             :   : mFillRule(aFillRule)
     133             :   , mContainingContext(nullptr)
     134           0 :   , mCurrentPoint(aCurrentPoint)
     135             : {
     136           0 :   mPathData.swap(aPathData);
     137           0 : }
     138             : 
     139           0 : PathCairo::PathCairo(cairo_t *aContext)
     140             :   : mFillRule(FillRule::FILL_WINDING)
     141           0 :   , mContainingContext(nullptr)
     142             : {
     143           0 :   cairo_path_t *path = cairo_copy_path(aContext);
     144             : 
     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           0 :   for (int i = 0; i < path->num_data; i++) {
     149           0 :     mPathData.push_back(path->data[i]);
     150             :   }
     151             : 
     152           0 :   cairo_path_destroy(path);
     153           0 : }
     154             : 
     155           0 : PathCairo::~PathCairo()
     156             : {
     157           0 :   if (mContainingContext) {
     158           0 :     cairo_destroy(mContainingContext);
     159             :   }
     160           0 : }
     161             : 
     162             : already_AddRefed<PathBuilder>
     163           0 : PathCairo::CopyToBuilder(FillRule aFillRule) const
     164             : {
     165           0 :   RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(aFillRule);
     166             : 
     167           0 :   builder->mPathData = mPathData;
     168           0 :   builder->mCurrentPoint = mCurrentPoint;
     169             : 
     170           0 :   return builder.forget();
     171             : }
     172             : 
     173             : already_AddRefed<PathBuilder>
     174           0 : PathCairo::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const
     175             : {
     176           0 :   RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(aFillRule);
     177             : 
     178           0 :   AppendPathToBuilder(builder, &aTransform);
     179           0 :   builder->mCurrentPoint = aTransform.TransformPoint(mCurrentPoint);
     180             : 
     181           0 :   return builder.forget();
     182             : }
     183             : 
     184             : bool
     185           0 : PathCairo::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
     186             : {
     187           0 :   Matrix inverse = aTransform;
     188           0 :   inverse.Invert();
     189           0 :   Point transformed = inverse.TransformPoint(aPoint);
     190             : 
     191           0 :   EnsureContainingContext(aTransform);
     192             : 
     193           0 :   return cairo_in_fill(mContainingContext, transformed.x, transformed.y);
     194             : }
     195             : 
     196             : bool
     197           0 : PathCairo::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
     198             :                                const Point &aPoint,
     199             :                                const Matrix &aTransform) const
     200             : {
     201           0 :   Matrix inverse = aTransform;
     202           0 :   inverse.Invert();
     203           0 :   Point transformed = inverse.TransformPoint(aPoint);
     204             : 
     205           0 :   EnsureContainingContext(aTransform);
     206             : 
     207           0 :   SetCairoStrokeOptions(mContainingContext, aStrokeOptions);
     208             : 
     209           0 :   return cairo_in_stroke(mContainingContext, transformed.x, transformed.y);
     210             : }
     211             : 
     212             : Rect
     213           0 : PathCairo::GetBounds(const Matrix &aTransform) const
     214             : {
     215           0 :   EnsureContainingContext(aTransform);
     216             : 
     217             :   double x1, y1, x2, y2;
     218             : 
     219           0 :   cairo_path_extents(mContainingContext, &x1, &y1, &x2, &y2);
     220           0 :   Rect bounds(Float(x1), Float(y1), Float(x2 - x1), Float(y2 - y1));
     221           0 :   return aTransform.TransformBounds(bounds);
     222             : }
     223             : 
     224             : Rect
     225           0 : PathCairo::GetStrokedBounds(const StrokeOptions &aStrokeOptions,
     226             :                             const Matrix &aTransform) const
     227             : {
     228           0 :   EnsureContainingContext(aTransform);
     229             : 
     230             :   double x1, y1, x2, y2;
     231             : 
     232           0 :   SetCairoStrokeOptions(mContainingContext, aStrokeOptions);
     233             : 
     234           0 :   cairo_stroke_extents(mContainingContext, &x1, &y1, &x2, &y2);
     235           0 :   Rect bounds((Float)x1, (Float)y1, (Float)(x2 - x1), (Float)(y2 - y1));
     236           0 :   return aTransform.TransformBounds(bounds);
     237             : }
     238             : 
     239             : void
     240           0 : PathCairo::StreamToSink(PathSink *aSink) const
     241             : {
     242           0 :   for (size_t i = 0; i < mPathData.size(); i++) {
     243           0 :     switch (mPathData[i].header.type) {
     244             :     case CAIRO_PATH_MOVE_TO:
     245           0 :       i++;
     246           0 :       aSink->MoveTo(Point(mPathData[i].point.x, mPathData[i].point.y));
     247           0 :       break;
     248             :     case CAIRO_PATH_LINE_TO:
     249           0 :       i++;
     250           0 :       aSink->LineTo(Point(mPathData[i].point.x, mPathData[i].point.y));
     251           0 :       break;
     252             :     case CAIRO_PATH_CURVE_TO:
     253           0 :       aSink->BezierTo(Point(mPathData[i + 1].point.x, mPathData[i + 1].point.y),
     254           0 :                       Point(mPathData[i + 2].point.x, mPathData[i + 2].point.y),
     255           0 :                       Point(mPathData[i + 3].point.x, mPathData[i + 3].point.y));
     256           0 :       i += 3;
     257           0 :       break;
     258             :     case CAIRO_PATH_CLOSE_PATH:
     259           0 :       aSink->Close();
     260           0 :       break;
     261             :     default:
     262             :       // Corrupt path data!
     263           0 :       MOZ_ASSERT(false);
     264             :     }
     265             :   }
     266           0 : }
     267             : 
     268             : void
     269           0 : PathCairo::EnsureContainingContext(const Matrix &aTransform) const
     270             : {
     271           0 :   if (mContainingContext) {
     272           0 :     if (mContainingTransform.ExactlyEquals(aTransform)) {
     273           0 :       return;
     274             :     }
     275             :   } else {
     276           0 :     mContainingContext = cairo_create(DrawTargetCairo::GetDummySurface());
     277             :   }
     278             : 
     279           0 :   mContainingTransform = aTransform;
     280             : 
     281             :   cairo_matrix_t mat;
     282           0 :   GfxMatrixToCairoMatrix(mContainingTransform, mat);
     283           0 :   cairo_set_matrix(mContainingContext, &mat);
     284             : 
     285           0 :   SetPathOnContext(mContainingContext);
     286             : }
     287             : 
     288             : void
     289           0 : PathCairo::SetPathOnContext(cairo_t *aContext) const
     290             : {
     291             :   // Needs the correct fill rule set.
     292           0 :   cairo_set_fill_rule(aContext, GfxFillRuleToCairoFillRule(mFillRule));
     293             : 
     294           0 :   cairo_new_path(aContext);
     295             : 
     296           0 :   if (mPathData.size()) {
     297             :     cairo_path_t path;
     298           0 :     path.data = const_cast<cairo_path_data_t*>(&mPathData.front());
     299           0 :     path.num_data = mPathData.size();
     300           0 :     path.status = CAIRO_STATUS_SUCCESS;
     301           0 :     cairo_append_path(aContext, &path);
     302             :   }
     303           0 : }
     304             : 
     305             : void
     306           0 : PathCairo::AppendPathToBuilder(PathBuilderCairo *aBuilder, const Matrix *aTransform) const
     307             : {
     308           0 :   if (aTransform) {
     309           0 :     size_t i = 0;
     310           0 :     while (i < mPathData.size()) {
     311           0 :       uint32_t pointCount = mPathData[i].header.length - 1;
     312           0 :       aBuilder->mPathData.push_back(mPathData[i]);
     313           0 :       i++;
     314           0 :       for (uint32_t c = 0; c < pointCount; c++) {
     315             :         cairo_path_data_t data;
     316           0 :         Point newPoint = aTransform->TransformPoint(Point(mPathData[i].point.x, mPathData[i].point.y));
     317           0 :         data.point.x = newPoint.x;
     318           0 :         data.point.y = newPoint.y;
     319           0 :         aBuilder->mPathData.push_back(data);
     320           0 :         i++;
     321             :       }
     322             :     }
     323             :   } else {
     324           0 :     for (size_t i = 0; i < mPathData.size(); i++) {
     325           0 :       aBuilder->mPathData.push_back(mPathData[i]);
     326             :     }
     327             :   }
     328           0 : }
     329             : 
     330             : } // namespace gfx
     331             : } // namespace mozilla

Generated by: LCOV version 1.13