LCOV - code coverage report
Current view: directory - gfx/2d - PathCairo.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 138 0 0.0 %
Date: 2012-06-02 Functions: 27 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2                 :  * ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Corporation code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2011
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *
      23                 :  * Alternatively, the contents of this file may be used under the terms of
      24                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      25                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      26                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      27                 :  * of those above. If you wish to allow use of your version of this file only
      28                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      29                 :  * use your version of this file under the terms of the MPL, indicate your
      30                 :  * decision by deleting the provisions above and replace them with the notice
      31                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      32                 :  * the provisions above, a recipient may use your version of this file under
      33                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      34                 :  *
      35                 :  * ***** END LICENSE BLOCK ***** */
      36                 : 
      37                 : #include "PathCairo.h"
      38                 : #include <math.h>
      39                 : #include "DrawTargetCairo.h"
      40                 : #include "Logging.h"
      41                 : #include "PathHelpers.h"
      42                 : #include "HelpersCairo.h"
      43                 : 
      44                 : namespace mozilla {
      45                 : namespace gfx {
      46                 : 
      47               0 : CairoPathContext::CairoPathContext(cairo_t* aCtx, DrawTargetCairo* aDrawTarget,
      48                 :                                    FillRule aFillRule,
      49                 :                                    const Matrix& aTransform /* = Matrix() */)
      50                 :  : mTransform(aTransform)
      51                 :  , mContext(aCtx)
      52                 :  , mDrawTarget(aDrawTarget)
      53               0 :  , mFillRule(aFillRule)
      54                 : {
      55               0 :   cairo_reference(mContext);
      56               0 :   cairo_set_fill_rule(mContext, GfxFillRuleToCairoFillRule(mFillRule));
      57                 : 
      58                 :   // If we don't have an identity transformation, we need to have a separate
      59                 :   // context from the draw target, because we can't set a transformation on its
      60                 :   // context.
      61               0 :   if (mDrawTarget && !mTransform.IsIdentity()) {
      62               0 :     DuplicateContextAndPath(mTransform);
      63                 : 
      64               0 :     ForgetDrawTarget();
      65               0 :   } else if (mDrawTarget) {
      66               0 :     mDrawTarget->SetPathObserver(this);
      67                 :   }
      68               0 : }
      69                 : 
      70               0 : CairoPathContext::~CairoPathContext()
      71                 : {
      72               0 :   if (mDrawTarget) {
      73               0 :     mDrawTarget->SetPathObserver(NULL);
      74                 :   }
      75               0 :   cairo_destroy(mContext);
      76               0 : }
      77                 : 
      78                 : void
      79               0 : CairoPathContext::DuplicateContextAndPath(const Matrix& aMatrix /* = Matrix() */)
      80                 : {
      81                 :   // Duplicate the path.
      82               0 :   cairo_path_t* path = cairo_copy_path(mContext);
      83               0 :   cairo_fill_rule_t rule = cairo_get_fill_rule(mContext);
      84                 : 
      85                 :   // Duplicate the context.
      86               0 :   cairo_surface_t* surf = cairo_get_target(mContext);
      87               0 :   cairo_destroy(mContext);
      88               0 :   mContext = cairo_create(surf);
      89                 : 
      90                 :   // Transform the context.
      91                 :   cairo_matrix_t matrix;
      92               0 :   GfxMatrixToCairoMatrix(aMatrix, matrix);
      93               0 :   cairo_transform(mContext, &matrix);
      94                 : 
      95                 :   // Add the path, and throw away our duplicate.
      96               0 :   cairo_append_path(mContext, path);
      97               0 :   cairo_set_fill_rule(mContext, rule);
      98               0 :   cairo_path_destroy(path);
      99               0 : }
     100                 : 
     101                 : void
     102               0 : CairoPathContext::PathWillChange()
     103                 : {
     104                 :   // Once we've copied out the context's path, there's no use to holding on to
     105                 :   // the draw target. Thus, there's nothing for us to do if we're independent
     106                 :   // of the draw target, since we'll have already copied out the context's
     107                 :   // path.
     108               0 :   if (mDrawTarget) {
     109                 :     // The context we point to is going to change from under us. To continue
     110                 :     // using this path, we need to copy it to a new context.
     111               0 :     DuplicateContextAndPath();
     112                 : 
     113               0 :     ForgetDrawTarget();
     114                 :   }
     115               0 : }
     116                 : 
     117                 : void
     118               0 : CairoPathContext::MatrixWillChange(const Matrix& aNewMatrix)
     119                 : {
     120                 :   // Cairo paths are stored in device space. Since we logically operate in user
     121                 :   // space, we want to make it so our path will be in the same location if and
     122                 :   // when our path is copied out.
     123                 :   // To effect this, we copy out our path (which, in Cairo, implicitly converts
     124                 :   // to user space), then temporarily set the context to have the new
     125                 :   // transform. We then set the path, which ensures that the points are all
     126                 :   // transformed correctly. Finally, we set the matrix back to its original
     127                 :   // value.
     128               0 :   cairo_path_t* path = cairo_copy_path(mContext);
     129                 : 
     130                 :   cairo_matrix_t origMatrix;
     131               0 :   cairo_get_matrix(mContext, &origMatrix);
     132                 : 
     133                 :   cairo_matrix_t newMatrix;
     134               0 :   GfxMatrixToCairoMatrix(aNewMatrix, newMatrix);
     135               0 :   cairo_set_matrix(mContext, &newMatrix);
     136                 : 
     137               0 :   cairo_new_path(mContext);
     138               0 :   cairo_append_path(mContext, path);
     139               0 :   cairo_path_destroy(path);
     140                 : 
     141               0 :   cairo_set_matrix(mContext, &origMatrix);
     142               0 : }
     143                 : 
     144                 : void
     145               0 : CairoPathContext::CopyPathTo(cairo_t* aToContext)
     146                 : {
     147               0 :   if (aToContext != mContext) {
     148               0 :     cairo_set_fill_rule(aToContext, GfxFillRuleToCairoFillRule(mFillRule));
     149                 : 
     150                 :     cairo_matrix_t origMat;
     151               0 :     cairo_get_matrix(aToContext, &origMat);
     152                 : 
     153                 :     cairo_matrix_t mat;
     154               0 :     GfxMatrixToCairoMatrix(mTransform, mat);
     155               0 :     cairo_transform(aToContext, &mat);
     156                 : 
     157                 :     // cairo_copy_path gives us a user-space copy of the path, so we don't have
     158                 :     // to worry about transformations here.
     159               0 :     cairo_path_t* path = cairo_copy_path(mContext);
     160               0 :     cairo_new_path(aToContext);
     161               0 :     cairo_append_path(aToContext, path);
     162               0 :     cairo_path_destroy(path);
     163                 : 
     164               0 :     cairo_set_matrix(aToContext, &origMat);
     165                 :   }
     166               0 : }
     167                 : 
     168                 : void
     169               0 : CairoPathContext::ForgetDrawTarget()
     170                 : {
     171               0 :   mDrawTarget = NULL;
     172               0 : }
     173                 : 
     174                 : bool
     175               0 : CairoPathContext::ContainsPath(const Path* aPath)
     176                 : {
     177               0 :   if (aPath->GetBackendType() != BACKEND_CAIRO) {
     178               0 :     return false;
     179                 :   }
     180                 : 
     181               0 :   const PathCairo* path = static_cast<const PathCairo*>(aPath);
     182               0 :   RefPtr<CairoPathContext> ctx = const_cast<PathCairo*>(path)->GetPathContext();
     183               0 :   return ctx == this;
     184                 : }
     185                 : 
     186               0 : PathBuilderCairo::PathBuilderCairo(CairoPathContext* aPathContext,
     187                 :                                    const Matrix& aTransform /* = Matrix() */)
     188               0 :  : mFillRule(aPathContext->GetFillRule())
     189                 : {
     190               0 :   RefPtr<DrawTargetCairo> drawTarget = aPathContext->GetDrawTarget();
     191                 :   mPathContext = new CairoPathContext(*aPathContext, drawTarget, mFillRule,
     192               0 :                                       aPathContext->GetTransform() * aTransform);
     193                 : 
     194                 :   // We need to ensure that we are allowed to modify the path currently set on
     195                 :   // aPathContext. If we don't have a draw target, CairoPathContext's
     196                 :   // constructor has no way to make aPathContext duplicate its path (normally,
     197                 :   // calling drawTarget->SetPathObserver() would do so). In this case, we
     198                 :   // explicitly make aPathContext copy out its context and path, leaving our
     199                 :   // path alone.
     200               0 :   if (!drawTarget) {
     201               0 :     aPathContext->DuplicateContextAndPath();
     202                 :   }
     203               0 : }
     204                 : 
     205               0 : PathBuilderCairo::PathBuilderCairo(cairo_t* aCtx, DrawTargetCairo* aDrawTarget, FillRule aFillRule)
     206               0 :  : mPathContext(new CairoPathContext(aCtx, aDrawTarget, aFillRule))
     207               0 :  , mFillRule(aFillRule)
     208               0 : {}
     209                 : 
     210                 : void
     211               0 : PathBuilderCairo::MoveTo(const Point &aPoint)
     212                 : {
     213               0 :   cairo_move_to(*mPathContext, aPoint.x, aPoint.y);
     214               0 : }
     215                 : 
     216                 : void
     217               0 : PathBuilderCairo::LineTo(const Point &aPoint)
     218                 : {
     219               0 :   cairo_line_to(*mPathContext, aPoint.x, aPoint.y);
     220               0 : }
     221                 : 
     222                 : void
     223               0 : PathBuilderCairo::BezierTo(const Point &aCP1,
     224                 :                            const Point &aCP2,
     225                 :                            const Point &aCP3)
     226                 : {
     227               0 :   cairo_curve_to(*mPathContext, aCP1.x, aCP1.y, aCP2.x, aCP2.y, aCP3.x, aCP3.y);
     228               0 : }
     229                 : 
     230                 : void
     231               0 : PathBuilderCairo::QuadraticBezierTo(const Point &aCP1,
     232                 :                                     const Point &aCP2)
     233                 : {
     234                 :   // We need to elevate the degree of this quadratic Bézier to cubic, so we're
     235                 :   // going to add an intermediate control point, and recompute control point 1.
     236                 :   // The first and last control points remain the same.
     237                 :   // This formula can be found on http://fontforge.sourceforge.net/bezier.html
     238               0 :   Point CP0 = CurrentPoint();
     239               0 :   Point CP1 = (CP0 + aCP1 * 2.0) / 3.0;
     240               0 :   Point CP2 = (aCP2 + aCP1 * 2.0) / 3.0;
     241               0 :   Point CP3 = aCP2;
     242                 : 
     243               0 :   cairo_curve_to(*mPathContext, CP1.x, CP1.y, CP2.x, CP2.y, CP3.x, CP3.y);
     244               0 : }
     245                 : 
     246                 : void
     247               0 : PathBuilderCairo::Close()
     248                 : {
     249               0 :   cairo_close_path(*mPathContext);
     250               0 : }
     251                 : 
     252                 : void
     253               0 : PathBuilderCairo::Arc(const Point &aOrigin, float aRadius, float aStartAngle,
     254                 :                      float aEndAngle, bool aAntiClockwise)
     255                 : {
     256               0 :   ArcToBezier(this, aOrigin, aRadius, aStartAngle, aEndAngle, aAntiClockwise);
     257               0 : }
     258                 : 
     259                 : Point
     260               0 : PathBuilderCairo::CurrentPoint() const
     261                 : {
     262                 :   double x, y;
     263               0 :   cairo_get_current_point(*mPathContext, &x, &y);
     264               0 :   return Point(x, y);
     265                 : }
     266                 : 
     267                 : TemporaryRef<Path>
     268               0 : PathBuilderCairo::Finish()
     269                 : {
     270               0 :   RefPtr<PathCairo> path = new PathCairo(*mPathContext,
     271               0 :                                          mPathContext->GetDrawTarget(),
     272                 :                                          mFillRule,
     273               0 :                                          mPathContext->GetTransform());
     274               0 :   return path;
     275                 : }
     276                 : 
     277                 : TemporaryRef<CairoPathContext>
     278               0 : PathBuilderCairo::GetPathContext()
     279                 : {
     280               0 :   return mPathContext;
     281                 : }
     282                 : 
     283               0 : PathCairo::PathCairo(cairo_t* aCtx, DrawTargetCairo* aDrawTarget, FillRule aFillRule, const Matrix& aTransform)
     284               0 :  : mPathContext(new CairoPathContext(aCtx, aDrawTarget, aFillRule, aTransform))
     285               0 :  , mFillRule(aFillRule)
     286               0 : {}
     287                 : 
     288                 : TemporaryRef<PathBuilder>
     289               0 : PathCairo::CopyToBuilder(FillRule aFillRule) const
     290                 : {
     291                 :   // Note: This PathBuilderCairo constructor causes our mPathContext to copy
     292                 :   // out the path, since the path builder is going to change the path on us.
     293               0 :   RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(mPathContext);
     294               0 :   return builder;
     295                 : }
     296                 : 
     297                 : TemporaryRef<PathBuilder>
     298               0 : PathCairo::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const
     299                 : {
     300                 :   // Note: This PathBuilderCairo constructor causes our mPathContext to copy
     301                 :   // out the path, since the path builder is going to change the path on us.
     302                 :   RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(mPathContext,
     303               0 :                                                           aTransform);
     304               0 :   return builder;
     305                 : }
     306                 : 
     307                 : bool
     308               0 : PathCairo::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
     309                 : {
     310               0 :   Matrix inverse = aTransform;
     311               0 :   inverse.Invert();
     312               0 :   Point transformed = inverse * aPoint;
     313                 : 
     314               0 :   return cairo_in_fill(*mPathContext, transformed.x, transformed.y);
     315                 : }
     316                 : 
     317                 : Rect
     318               0 : PathCairo::GetBounds(const Matrix &aTransform) const
     319                 : {
     320                 :   double x1, y1, x2, y2;
     321                 : 
     322               0 :   cairo_path_extents(*mPathContext, &x1, &y1, &x2, &y2);
     323               0 :   Rect bounds(x1, y1, x2 - x1, y2 - y1);
     324               0 :   return aTransform.TransformBounds(bounds);
     325                 : }
     326                 : 
     327                 : Rect
     328               0 : PathCairo::GetStrokedBounds(const StrokeOptions &aStrokeOptions,
     329                 :                             const Matrix &aTransform) const
     330                 : {
     331                 :   double x1, y1, x2, y2;
     332                 : 
     333               0 :   SetCairoStrokeOptions(*mPathContext, aStrokeOptions);
     334                 : 
     335               0 :   cairo_stroke_extents(*mPathContext, &x1, &y1, &x2, &y2);
     336               0 :   Rect bounds(x1, y1, x2 - x1, y2 - y1);
     337               0 :   return aTransform.TransformBounds(bounds);
     338                 : }
     339                 : 
     340                 : TemporaryRef<CairoPathContext>
     341               0 : PathCairo::GetPathContext()
     342                 : {
     343               0 :   return mPathContext;
     344                 : }
     345                 : 
     346                 : void
     347               0 : PathCairo::CopyPathTo(cairo_t* aContext, DrawTargetCairo* aDrawTarget)
     348                 : {
     349               0 :   if (mPathContext->GetContext() != aContext) {
     350               0 :     mPathContext->CopyPathTo(aContext);
     351                 : 
     352                 :     // Since aDrawTarget wants us to be the current path on its context, we
     353                 :     // should also listen to it for updates to that path (as an optimization).
     354                 :     // The easiest way to do this is to just recreate mPathContext, since it
     355                 :     // registers with aDrawTarget for updates.
     356                 :     mPathContext = new CairoPathContext(aContext, aDrawTarget,
     357               0 :                                         mPathContext->GetFillRule(),
     358               0 :                                         mPathContext->GetTransform());
     359                 :   }
     360               0 : }
     361                 : 
     362                 : }
     363                 : }

Generated by: LCOV version 1.7