gfx/thebes/gfxPattern.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 /* -*- 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 "gfxTypes.h"
     7 #include "gfxPattern.h"
     8 #include "gfxASurface.h"
     9 #include "gfxPlatform.h"
    10 #include "gfx2DGlue.h"
    11 #include "gfxGradientCache.h"
    13 #include "cairo.h"
    15 #include <vector>
    17 using namespace mozilla::gfx;
    19 gfxPattern::gfxPattern(cairo_pattern_t *aPattern)
    20   : mGfxPattern(nullptr)
    21 {
    22     mPattern = cairo_pattern_reference(aPattern);
    23 }
    25 gfxPattern::gfxPattern(const gfxRGBA& aColor)
    26   : mGfxPattern(nullptr)
    27 {
    28     mPattern = cairo_pattern_create_rgba(aColor.r, aColor.g, aColor.b, aColor.a);
    29 }
    31 // from another surface
    32 gfxPattern::gfxPattern(gfxASurface *surface)
    33   : mGfxPattern(nullptr)
    34 {
    35     mPattern = cairo_pattern_create_for_surface(surface->CairoSurface());
    36 }
    38 // linear
    39 gfxPattern::gfxPattern(gfxFloat x0, gfxFloat y0, gfxFloat x1, gfxFloat y1)
    40   : mGfxPattern(nullptr)
    41 {
    42     mPattern = cairo_pattern_create_linear(x0, y0, x1, y1);
    43 }
    45 // radial
    46 gfxPattern::gfxPattern(gfxFloat cx0, gfxFloat cy0, gfxFloat radius0,
    47                        gfxFloat cx1, gfxFloat cy1, gfxFloat radius1)
    48   : mGfxPattern(nullptr)
    49 {
    50     mPattern = cairo_pattern_create_radial(cx0, cy0, radius0,
    51                                            cx1, cy1, radius1);
    52 }
    54 // Azure
    55 gfxPattern::gfxPattern(SourceSurface *aSurface, const Matrix &aTransform)
    56   : mPattern(nullptr)
    57   , mGfxPattern(nullptr)
    58   , mSourceSurface(aSurface)
    59   , mTransform(aTransform)
    60   , mExtend(EXTEND_NONE)
    61 {
    62 }
    64 gfxPattern::~gfxPattern()
    65 {
    66     cairo_pattern_destroy(mPattern);
    68     if (mGfxPattern) {
    69       mGfxPattern->~Pattern();
    70     }
    71 }
    73 cairo_pattern_t *
    74 gfxPattern::CairoPattern()
    75 {
    76     return mPattern;
    77 }
    79 void
    80 gfxPattern::AddColorStop(gfxFloat offset, const gfxRGBA& c)
    81 {
    82   if (mPattern) {
    83     mStops = nullptr;
    84     if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
    85         gfxRGBA cms;
    86         qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
    87         if (transform)
    88           gfxPlatform::TransformPixel(c, cms, transform);
    90         // Use the original alpha to avoid unnecessary float->byte->float
    91         // conversion errors
    92         cairo_pattern_add_color_stop_rgba(mPattern, offset,
    93                                           cms.r, cms.g, cms.b, c.a);
    94     }
    95     else
    96         cairo_pattern_add_color_stop_rgba(mPattern, offset, c.r, c.g, c.b, c.a);
    97   }
    98 }
   100 void
   101 gfxPattern::SetColorStops(mozilla::RefPtr<mozilla::gfx::GradientStops> aStops)
   102 {
   103   mStops = aStops;
   104 }
   106 void
   107 gfxPattern::CacheColorStops(mozilla::gfx::DrawTarget *aDT)
   108 {
   109   if (mPattern) {
   110     mStops = nullptr;
   111     nsTArray<GradientStop> stops;
   112     int count = 0;
   113     cairo_pattern_get_color_stop_count(mPattern, &count);
   114     stops.SetLength(count);
   115     for (int n = 0; n < count; ++n) {
   116       double offset, r, g, b, a;
   117       cairo_pattern_get_color_stop_rgba(mPattern, n, &offset, &r, &g, &b, &a);
   118       stops[n].color = mozilla::gfx::Color(r, g, b, a);
   119       stops[n].offset = offset;
   120     }
   121     mStops = gfxGradientCache::GetOrCreateGradientStops(aDT,
   122                                                         stops,
   123                                                         (cairo_pattern_get_extend(mPattern) == CAIRO_EXTEND_REPEAT)
   124                                                         ? mozilla::gfx::ExtendMode::REPEAT
   125                                                         : mozilla::gfx::ExtendMode::CLAMP);
   126   }
   127 }
   129 void
   130 gfxPattern::SetMatrix(const gfxMatrix& matrix)
   131 {
   132   if (mPattern) {
   133     cairo_matrix_t mat = *reinterpret_cast<const cairo_matrix_t*>(&matrix);
   134     cairo_pattern_set_matrix(mPattern, &mat);
   135   } else {
   136     mTransform = ToMatrix(matrix);
   137     // Cairo-pattern matrices specify the conversion from DrawTarget to pattern
   138     // space. Azure pattern matrices specify the conversion from pattern to
   139     // DrawTarget space.
   140     mTransform.Invert();
   141   }
   142 }
   144 gfxMatrix
   145 gfxPattern::GetMatrix() const
   146 {
   147   if (mPattern) {
   148     cairo_matrix_t mat;
   149     cairo_pattern_get_matrix(mPattern, &mat);
   150     return gfxMatrix(*reinterpret_cast<gfxMatrix*>(&mat));
   151   } else {
   152     // invert at the higher precision of gfxMatrix
   153     // cause we need to convert at some point anyways
   154     gfxMatrix mat = ThebesMatrix(mTransform);
   155     mat.Invert();
   156     return mat;
   157   }
   158 }
   160 gfxMatrix
   161 gfxPattern::GetInverseMatrix() const
   162 {
   163   if (mPattern) {
   164     cairo_matrix_t mat;
   165     cairo_pattern_get_matrix(mPattern, &mat);
   166     cairo_matrix_invert(&mat);
   167     return gfxMatrix(*reinterpret_cast<gfxMatrix*>(&mat));
   168   } else {
   169     return ThebesMatrix(mTransform);
   170   }
   171 }
   173 Pattern*
   174 gfxPattern::GetPattern(DrawTarget *aTarget, Matrix *aPatternTransform)
   175 {
   176   if (mGfxPattern) {
   177     mGfxPattern->~Pattern();
   178     mGfxPattern = nullptr;
   179   }
   181   if (!mPattern) {
   182     Matrix adjustedMatrix = mTransform;
   183     if (aPatternTransform)
   184       AdjustTransformForPattern(adjustedMatrix, aTarget->GetTransform(), aPatternTransform);
   185     mGfxPattern = new (mSurfacePattern.addr())
   186       SurfacePattern(mSourceSurface, ToExtendMode(mExtend), adjustedMatrix, mFilter);
   187     return mGfxPattern;
   188   }
   190   GraphicsExtend extend = (GraphicsExtend)cairo_pattern_get_extend(mPattern);
   192   switch (cairo_pattern_get_type(mPattern)) {
   193   case CAIRO_PATTERN_TYPE_SOLID:
   194     {
   195       double r, g, b, a;
   196       cairo_pattern_get_rgba(mPattern, &r, &g, &b, &a);
   198       new (mColorPattern.addr()) ColorPattern(Color(r, g, b, a));
   199       return mColorPattern.addr();
   200     }
   201   case CAIRO_PATTERN_TYPE_SURFACE:
   202     {
   203       GraphicsFilter filter = (GraphicsFilter)cairo_pattern_get_filter(mPattern);
   204       cairo_matrix_t mat;
   205       cairo_pattern_get_matrix(mPattern, &mat);
   206       gfxMatrix matrix(*reinterpret_cast<gfxMatrix*>(&mat));
   208       cairo_surface_t *surf = nullptr;
   209       cairo_pattern_get_surface(mPattern, &surf);
   211       if (!mSourceSurface) {
   212         nsRefPtr<gfxASurface> gfxSurf = gfxASurface::Wrap(surf);
   213         // The underlying surface here will be kept around by the gfxPattern.
   214         // This function is intended to be used right away.
   215         mSourceSurface =
   216           gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(aTarget, gfxSurf);
   217       }
   219       if (mSourceSurface) {
   220         Matrix newMat = ToMatrix(matrix);
   222         AdjustTransformForPattern(newMat, aTarget->GetTransform(), aPatternTransform);
   224         double x, y;
   225         cairo_surface_get_device_offset(surf, &x, &y);
   226         newMat.Translate(-x, -y);
   227         mGfxPattern = new (mSurfacePattern.addr())
   228           SurfacePattern(mSourceSurface, ToExtendMode(extend), newMat, ToFilter(filter));
   229         return mGfxPattern;
   230       }
   231       break;
   232     }
   233   case CAIRO_PATTERN_TYPE_LINEAR:
   234     {
   235       double x1, y1, x2, y2;
   236       cairo_pattern_get_linear_points(mPattern, &x1, &y1, &x2, &y2);
   237       if (!mStops) {
   238         int count = 0;
   239         cairo_pattern_get_color_stop_count(mPattern, &count);
   241         std::vector<GradientStop> stops;
   243         for (int i = 0; i < count; i++) {
   244           GradientStop stop;
   245           double r, g, b, a, offset;
   246           cairo_pattern_get_color_stop_rgba(mPattern, i, &offset, &r, &g, &b, &a);
   248           stop.offset = offset;
   249           stop.color = Color(Float(r), Float(g), Float(b), Float(a));
   250           stops.push_back(stop);
   251         }
   253         mStops = aTarget->CreateGradientStops(&stops.front(), count, ToExtendMode(extend));
   254       }
   256       if (mStops) {
   257         cairo_matrix_t mat;
   258         cairo_pattern_get_matrix(mPattern, &mat);
   259         gfxMatrix matrix(*reinterpret_cast<gfxMatrix*>(&mat));
   261         Matrix newMat = ToMatrix(matrix);
   263         AdjustTransformForPattern(newMat, aTarget->GetTransform(), aPatternTransform);
   265         mGfxPattern = new (mLinearGradientPattern.addr())
   266           LinearGradientPattern(Point(x1, y1), Point(x2, y2), mStops, newMat);
   268         return mGfxPattern;
   269       }
   270       break;
   271     }
   272   case CAIRO_PATTERN_TYPE_RADIAL:
   273     {
   274       if (!mStops) {
   275         int count = 0;
   276         cairo_pattern_get_color_stop_count(mPattern, &count);
   278         std::vector<GradientStop> stops;
   280         for (int i = 0; i < count; i++) {
   281           GradientStop stop;
   282           double r, g, b, a, offset;
   283           cairo_pattern_get_color_stop_rgba(mPattern, i, &offset, &r, &g, &b, &a);
   285           stop.offset = offset;
   286           stop.color = Color(Float(r), Float(g), Float(b), Float(a));
   287           stops.push_back(stop);
   288         }
   290         mStops = aTarget->CreateGradientStops(&stops.front(), count, ToExtendMode(extend));
   291       }
   293       if (mStops) {
   294         cairo_matrix_t mat;
   295         cairo_pattern_get_matrix(mPattern, &mat);
   296         gfxMatrix matrix(*reinterpret_cast<gfxMatrix*>(&mat));
   298         Matrix newMat = ToMatrix(matrix);
   300         AdjustTransformForPattern(newMat, aTarget->GetTransform(), aPatternTransform);
   302         double x1, y1, x2, y2, r1, r2;
   303         cairo_pattern_get_radial_circles(mPattern, &x1, &y1, &r1, &x2, &y2, &r2);
   304         mGfxPattern = new (mRadialGradientPattern.addr())
   305           RadialGradientPattern(Point(x1, y1), Point(x2, y2), r1, r2, mStops, newMat);
   307         return mGfxPattern;
   308       }
   309       break;
   310     }
   311   default:
   312     /* Reassure the compiler we are handling all the enum values.  */
   313     break;
   314   }
   316   new (mColorPattern.addr()) ColorPattern(Color(0, 0, 0, 0));
   317   return mColorPattern.addr();
   318 }
   320 void
   321 gfxPattern::SetExtend(GraphicsExtend extend)
   322 {
   323   if (mPattern) {
   324     mStops = nullptr;
   325     if (extend == EXTEND_PAD_EDGE) {
   326         if (cairo_pattern_get_type(mPattern) == CAIRO_PATTERN_TYPE_SURFACE) {
   327             cairo_surface_t *surf = nullptr;
   329             cairo_pattern_get_surface (mPattern, &surf);
   330             if (surf) {
   331                 switch (cairo_surface_get_type(surf)) {
   332                     case CAIRO_SURFACE_TYPE_WIN32_PRINTING:
   333                     case CAIRO_SURFACE_TYPE_QUARTZ:
   334                         extend = EXTEND_NONE;
   335                         break;
   337                     case CAIRO_SURFACE_TYPE_WIN32:
   338                     case CAIRO_SURFACE_TYPE_XLIB:
   339                     default:
   340                         extend = EXTEND_PAD;
   341                         break;
   342                 }
   343             }
   344         }
   346         // if something went wrong, or not a surface pattern, use PAD
   347         if (extend == EXTEND_PAD_EDGE)
   348             extend = EXTEND_PAD;
   349     }
   351     cairo_pattern_set_extend(mPattern, (cairo_extend_t)extend);
   352   } else {
   353     // This is always a surface pattern and will default to EXTEND_PAD
   354     // for EXTEND_PAD_EDGE.
   355     mExtend = extend;
   356   }
   357 }
   359 bool
   360 gfxPattern::IsOpaque()
   361 {
   362   if (mPattern) {
   363     switch (cairo_pattern_get_type(mPattern)) {
   364     case CAIRO_PATTERN_TYPE_SURFACE:
   365       {
   366         cairo_surface_t *surf = nullptr;
   367         cairo_pattern_get_surface(mPattern, &surf);
   369         if (cairo_surface_get_content(surf) == CAIRO_CONTENT_COLOR) {
   370           return true;
   371         }
   372       }
   373     default:
   374       return false;
   375     }
   376   }
   378   if (mSourceSurface->GetFormat() == SurfaceFormat::B8G8R8X8) {
   379     return true;
   380   }
   381   return false;
   382 }
   384 gfxPattern::GraphicsExtend
   385 gfxPattern::Extend() const
   386 {
   387   if (mPattern) {
   388     return (GraphicsExtend)cairo_pattern_get_extend(mPattern);
   389   } else {
   390     return mExtend;
   391   }
   392 }
   394 void
   395 gfxPattern::SetFilter(GraphicsFilter filter)
   396 {
   397   if (mPattern) {
   398     cairo_pattern_set_filter(mPattern, (cairo_filter_t)(int)filter);
   399   } else {
   400     mFilter = ToFilter(filter);
   401   }
   402 }
   404 GraphicsFilter
   405 gfxPattern::Filter() const
   406 {
   407   if (mPattern) {
   408     return (GraphicsFilter)cairo_pattern_get_filter(mPattern);
   409   } else {
   410     return ThebesFilter(mFilter);
   411   }
   412 }
   414 bool
   415 gfxPattern::GetSolidColor(gfxRGBA& aColor)
   416 {
   417     return cairo_pattern_get_rgba(mPattern,
   418                                   &aColor.r,
   419                                   &aColor.g,
   420                                   &aColor.b,
   421                                   &aColor.a) == CAIRO_STATUS_SUCCESS;
   422 }
   424 already_AddRefed<gfxASurface>
   425 gfxPattern::GetSurface()
   426 {
   427   if (mPattern) {
   428     cairo_surface_t *surf = nullptr;
   430     if (cairo_pattern_get_surface (mPattern, &surf) != CAIRO_STATUS_SUCCESS)
   431         return nullptr;
   433     return gfxASurface::Wrap(surf);
   434   } else {
   435     // We should never be trying to get the surface off an Azure gfx Pattern.
   436     NS_ERROR("Attempt to get surface off an Azure gfxPattern!");
   437     return nullptr;
   438   }
   439 }
   441 gfxPattern::GraphicsPatternType
   442 gfxPattern::GetType() const
   443 {
   444   if (mPattern) {
   445     return (GraphicsPatternType) cairo_pattern_get_type(mPattern);
   446   } else {
   447     // We should never be trying to get the type off an Azure gfx Pattern.
   448     MOZ_ASSERT(0);
   449     return PATTERN_SURFACE;
   450   }
   451 }
   453 int
   454 gfxPattern::CairoStatus()
   455 {
   456   if (mPattern) {
   457     return cairo_pattern_status(mPattern);
   458   } else {
   459     // An Azure pattern as this point is never in error status.
   460     return CAIRO_STATUS_SUCCESS;
   461   }
   462 }
   464 void
   465 gfxPattern::AdjustTransformForPattern(Matrix &aPatternTransform,
   466                                       const Matrix &aCurrentTransform,
   467                                       const Matrix *aOriginalTransform)
   468 {
   469   aPatternTransform.Invert();
   470   if (!aOriginalTransform) {
   471     // User space is unchanged, so to get from pattern space to user space,
   472     // just invert the cairo matrix.
   473     aPatternTransform.NudgeToIntegers();
   474     return;
   475   }
   476   // aPatternTransform now maps from pattern space to the user space defined
   477   // by *aOriginalTransform.
   479   Matrix mat = aCurrentTransform;
   480   mat.Invert();
   481   // mat maps from device space to current user space
   483   // First, transform from pattern space to original user space. Then transform
   484   // from original user space to device space. Then transform from
   485   // device space to current user space.
   486   aPatternTransform = aPatternTransform * *aOriginalTransform * mat;
   487   aPatternTransform.NudgeToIntegers();
   488 }

mercurial