LCOV - code coverage report
Current view: top level - layout/svg - SVGContextPaint.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 41 147 27.9 %
Date: 2017-07-14 16:53:18 Functions: 6 13 46.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "SVGContextPaint.h"
       6             : 
       7             : #include "gfxContext.h"
       8             : #include "gfxUtils.h"
       9             : #include "mozilla/gfx/2D.h"
      10             : #include "mozilla/Preferences.h"
      11             : #include "nsIDocument.h"
      12             : #include "nsSVGPaintServerFrame.h"
      13             : #include "nsSVGEffects.h"
      14             : #include "nsSVGPaintServerFrame.h"
      15             : 
      16             : using namespace mozilla::gfx;
      17             : using namespace mozilla::image;
      18             : 
      19             : namespace mozilla {
      20             : 
      21             : using image::imgDrawingParams;
      22             : 
      23             : /* static */ bool
      24          53 : SVGContextPaint::IsAllowedForImageFromURI(nsIURI* aURI)
      25             : {
      26             :   static bool sEnabledForContent = false;
      27             :   static bool sEnabledForContentCached = false;
      28             : 
      29          53 :   if (!sEnabledForContentCached) {
      30             :     Preferences::AddBoolVarCache(&sEnabledForContent,
      31           1 :                                  "svg.context-properties.content.enabled", false);
      32           1 :     sEnabledForContentCached = true;
      33             :   }
      34             : 
      35          53 :   if (sEnabledForContent) {
      36           0 :     return true;
      37             :   }
      38             : 
      39             :   // Context paint is pref'ed off for Web content.  Ideally we'd have some
      40             :   // easy means to determine whether the frame that has linked to the image
      41             :   // is a frame for a content node that originated from Web content.
      42             :   // Unfortunately different types of anonymous content, about: documents
      43             :   // such as about:reader, etc. that are "our" code that we ship are
      44             :   // sometimes hard to distinguish from real Web content.  As a result,
      45             :   // instead of trying to figure out what content is "ours" we instead let
      46             :   // any content provide image context paint, but only if the image is
      47             :   // chrome:// or resource:// do we return true.  This should be sufficient
      48             :   // to stop the image context paint feature being useful to (and therefore
      49             :   // used by and relied upon by) Web content.  (We don't want Web content to
      50             :   // use this feature because we're not sure that image context paint is a
      51             :   // good mechanism for wider use, or suitable for specification.)
      52             :   //
      53             :   // One case that is not covered by chrome:// or resource:// are WebExtensions,
      54             :   // specifically ones that are "ours". WebExtensions are moz-extension://
      55             :   // regardless if the extension is in-tree or not. Since we don't want
      56             :   // extension developers coming to rely on image context paint either, we only
      57             :   // enable context-paint for extensions that are signed by Mozilla.
      58             :   //
      59         106 :   nsAutoCString scheme;
      60         159 :   if (NS_SUCCEEDED(aURI->GetScheme(scheme)) &&
      61          53 :       (scheme.EqualsLiteral("chrome") || scheme.EqualsLiteral("resource"))) {
      62          53 :     return true;
      63             :   }
      64           0 :   RefPtr<BasePrincipal> principal = BasePrincipal::CreateCodebasePrincipal(aURI, OriginAttributes());
      65           0 :   nsString addonId;
      66           0 :   if (NS_SUCCEEDED(principal->GetAddonId(addonId))) {
      67           0 :     return StringEndsWith(addonId, NS_LITERAL_STRING("@mozilla.org"));
      68             :   }
      69           0 :   return false;
      70             : }
      71             : 
      72             : /**
      73             :  * Stores in |aTargetPaint| information on how to reconstruct the current
      74             :  * fill or stroke pattern. Will also set the paint opacity to transparent if
      75             :  * the paint is set to "none".
      76             :  * @param aOuterContextPaint pattern information from the outer text context
      77             :  * @param aTargetPaint where to store the current pattern information
      78             :  * @param aFillOrStroke member pointer to the paint we are setting up
      79             :  * @param aProperty the frame property descriptor of the fill or stroke paint
      80             :  *   server frame
      81             :  */
      82             : static void
      83           0 : SetupInheritablePaint(const DrawTarget* aDrawTarget,
      84             :                       const gfxMatrix& aContextMatrix,
      85             :                       nsIFrame* aFrame,
      86             :                       float& aOpacity,
      87             :                       SVGContextPaint* aOuterContextPaint,
      88             :                       SVGContextPaintImpl::Paint& aTargetPaint,
      89             :                       nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
      90             :                       nsSVGEffects::PaintingPropertyDescriptor aProperty,
      91             :                       imgDrawingParams& aImgParams)
      92             : {
      93           0 :   const nsStyleSVG *style = aFrame->StyleSVG();
      94             :   nsSVGPaintServerFrame *ps =
      95           0 :     nsSVGEffects::GetPaintServer(aFrame, aFillOrStroke, aProperty);
      96             : 
      97           0 :   if (ps) {
      98             :     RefPtr<gfxPattern> pattern =
      99           0 :       ps->GetPaintServerPattern(aFrame, aDrawTarget, aContextMatrix,
     100           0 :                                 aFillOrStroke, aOpacity, aImgParams);
     101             : 
     102           0 :     if (pattern) {
     103           0 :       aTargetPaint.SetPaintServer(aFrame, aContextMatrix, ps);
     104           0 :       return;
     105             :     }
     106             :   }
     107             : 
     108           0 :   if (aOuterContextPaint) {
     109           0 :     RefPtr<gfxPattern> pattern;
     110           0 :     switch ((style->*aFillOrStroke).Type()) {
     111             :     case eStyleSVGPaintType_ContextFill:
     112             :       pattern =
     113           0 :         aOuterContextPaint->GetFillPattern(aDrawTarget, aOpacity,
     114           0 :                                            aContextMatrix, aImgParams);
     115           0 :       break;
     116             :     case eStyleSVGPaintType_ContextStroke:
     117             :        pattern =
     118           0 :          aOuterContextPaint->GetStrokePattern(aDrawTarget, aOpacity,
     119           0 :                                               aContextMatrix, aImgParams);
     120           0 :       break;
     121             :     default:
     122             :       ;
     123             :     }
     124           0 :     if (pattern) {
     125           0 :       aTargetPaint.SetContextPaint(aOuterContextPaint, (style->*aFillOrStroke).Type());
     126           0 :       return;
     127             :     }
     128             :   }
     129             : 
     130             :   nscolor color =
     131           0 :     nsSVGUtils::GetFallbackOrPaintColor(aFrame->StyleContext(), aFillOrStroke);
     132           0 :   aTargetPaint.SetColor(color);
     133             : }
     134             : 
     135             : DrawMode
     136           0 : SVGContextPaintImpl::Init(const DrawTarget* aDrawTarget,
     137             :                           const gfxMatrix& aContextMatrix,
     138             :                           nsIFrame* aFrame,
     139             :                           SVGContextPaint* aOuterContextPaint,
     140             :                           imgDrawingParams& aImgParams)
     141             : {
     142           0 :   DrawMode toDraw = DrawMode(0);
     143             : 
     144           0 :   const nsStyleSVG *style = aFrame->StyleSVG();
     145             : 
     146             :   // fill:
     147           0 :   if (style->mFill.Type() == eStyleSVGPaintType_None) {
     148           0 :     SetFillOpacity(0.0f);
     149             :   } else {
     150           0 :     float opacity = nsSVGUtils::GetOpacity(style->FillOpacitySource(),
     151             :                                            style->mFillOpacity,
     152           0 :                                            aOuterContextPaint);
     153             : 
     154           0 :     SetupInheritablePaint(aDrawTarget, aContextMatrix, aFrame, opacity,
     155             :                           aOuterContextPaint, mFillPaint, &nsStyleSVG::mFill,
     156           0 :                           nsSVGEffects::FillProperty(), aImgParams);
     157             : 
     158           0 :     SetFillOpacity(opacity);
     159             : 
     160           0 :     toDraw |= DrawMode::GLYPH_FILL;
     161             :   }
     162             : 
     163             :   // stroke:
     164           0 :   if (style->mStroke.Type() == eStyleSVGPaintType_None) {
     165           0 :     SetStrokeOpacity(0.0f);
     166             :   } else {
     167           0 :     float opacity = nsSVGUtils::GetOpacity(style->StrokeOpacitySource(),
     168             :                                            style->mStrokeOpacity,
     169           0 :                                            aOuterContextPaint);
     170             : 
     171           0 :     SetupInheritablePaint(aDrawTarget, aContextMatrix, aFrame, opacity,
     172             :                           aOuterContextPaint, mStrokePaint,
     173             :                           &nsStyleSVG::mStroke, nsSVGEffects::StrokeProperty(),
     174           0 :                           aImgParams);
     175             : 
     176           0 :     SetStrokeOpacity(opacity);
     177             : 
     178           0 :     toDraw |= DrawMode::GLYPH_STROKE;
     179             :   }
     180             : 
     181           0 :   return toDraw;
     182             : }
     183             : 
     184             : void
     185           0 : SVGContextPaint::InitStrokeGeometry(gfxContext* aContext,
     186             :                                     float devUnitsPerSVGUnit)
     187             : {
     188           0 :   mStrokeWidth = aContext->CurrentLineWidth() / devUnitsPerSVGUnit;
     189           0 :   aContext->CurrentDash(mDashes, &mDashOffset);
     190           0 :   for (uint32_t i = 0; i < mDashes.Length(); i++) {
     191           0 :     mDashes[i] /= devUnitsPerSVGUnit;
     192             :   }
     193           0 :   mDashOffset /= devUnitsPerSVGUnit;
     194           0 : }
     195             : 
     196             : /* static */ SVGContextPaint*
     197          68 : SVGContextPaint::GetContextPaint(nsIContent* aContent)
     198             : {
     199          68 :   nsIDocument* ownerDoc = aContent->OwnerDoc();
     200             : 
     201          68 :   if (!ownerDoc->IsBeingUsedAsImage()) {
     202           0 :     return nullptr;
     203             :   }
     204             : 
     205             :   // XXX The SVGContextPaint that was passed to SetProperty was const. Ideally
     206             :   // we could and should re-apply that constness to the SVGContextPaint that
     207             :   // we get here (SVGImageContext is never changed after it is initialized).
     208             :   // Unfortunately lazy initialization of SVGContextPaint (which is a member of
     209             :   // SVGImageContext, and also conceptually never changes after construction)
     210             :   // prevents some of SVGContextPaint's conceptually const methods from being
     211             :   // const.  Trying to fix SVGContextPaint (perhaps by using |mutable|) is a
     212             :   // bit of a headache so for now we punt on that, don't reapply the constness
     213             :   // to the SVGContextPaint here, and trust that no one will add code that
     214             :   // actually modifies the object.
     215             : 
     216             :   return static_cast<SVGContextPaint*>(
     217          68 :            ownerDoc->GetProperty(nsGkAtoms::svgContextPaint));
     218             : }
     219             : 
     220             : already_AddRefed<gfxPattern>
     221           0 : SVGContextPaintImpl::GetFillPattern(const DrawTarget* aDrawTarget,
     222             :                                     float aOpacity,
     223             :                                     const gfxMatrix& aCTM,
     224             :                                     imgDrawingParams& aImgParams)
     225             : {
     226             :   return mFillPaint.GetPattern(aDrawTarget, aOpacity, &nsStyleSVG::mFill, aCTM,
     227           0 :                                aImgParams);
     228             : }
     229             : 
     230             : already_AddRefed<gfxPattern>
     231           0 : SVGContextPaintImpl::GetStrokePattern(const DrawTarget* aDrawTarget,
     232             :                                       float aOpacity,
     233             :                                       const gfxMatrix& aCTM,
     234             :                                       imgDrawingParams& aImgParams)
     235             : {
     236             :   return mStrokePaint.GetPattern(aDrawTarget, aOpacity, &nsStyleSVG::mStroke,
     237           0 :                                  aCTM, aImgParams);
     238             : }
     239             : 
     240             : already_AddRefed<gfxPattern>
     241           0 : SVGContextPaintImpl::Paint::GetPattern(const DrawTarget* aDrawTarget,
     242             :                                        float aOpacity,
     243             :                                        nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
     244             :                                        const gfxMatrix& aCTM,
     245             :                                        imgDrawingParams& aImgParams)
     246             : {
     247           0 :   RefPtr<gfxPattern> pattern;
     248           0 :   if (mPatternCache.Get(aOpacity, getter_AddRefs(pattern))) {
     249             :     // Set the pattern matrix just in case it was messed with by a previous
     250             :     // caller. We should get the same matrix each time a pattern is constructed
     251             :     // so this should be fine.
     252           0 :     pattern->SetMatrix(aCTM * mPatternMatrix);
     253           0 :     return pattern.forget();
     254             :   }
     255             : 
     256           0 :   switch (mPaintType) {
     257             :   case eStyleSVGPaintType_None:
     258           0 :     pattern = new gfxPattern(Color());
     259           0 :     mPatternMatrix = gfxMatrix();
     260           0 :     break;
     261             :   case eStyleSVGPaintType_Color: {
     262           0 :     Color color = Color::FromABGR(mPaintDefinition.mColor);
     263           0 :     color.a *= aOpacity;
     264           0 :     pattern = new gfxPattern(color);
     265           0 :     mPatternMatrix = gfxMatrix();
     266           0 :     break;
     267             :   }
     268             :   case eStyleSVGPaintType_Server:
     269             :     pattern =
     270           0 :       mPaintDefinition.mPaintServerFrame->GetPaintServerPattern(mFrame,
     271             :                                                                 aDrawTarget,
     272             :                                                                 mContextMatrix,
     273             :                                                                 aFillOrStroke,
     274             :                                                                 aOpacity,
     275           0 :                                                                 aImgParams);
     276             :     {
     277             :       // m maps original-user-space to pattern space
     278           0 :       gfxMatrix m = pattern->GetMatrix();
     279           0 :       gfxMatrix deviceToOriginalUserSpace = mContextMatrix;
     280           0 :       if (!deviceToOriginalUserSpace.Invert()) {
     281           0 :         return nullptr;
     282             :       }
     283             :       // mPatternMatrix maps device space to pattern space via original user space
     284           0 :       mPatternMatrix = deviceToOriginalUserSpace * m;
     285             :     }
     286           0 :     pattern->SetMatrix(aCTM * mPatternMatrix);
     287           0 :     break;
     288             :   case eStyleSVGPaintType_ContextFill:
     289             :     pattern =
     290           0 :       mPaintDefinition.mContextPaint->GetFillPattern(aDrawTarget,
     291             :                                                      aOpacity, aCTM,
     292           0 :                                                      aImgParams);
     293             :     // Don't cache this. mContextPaint will have cached it anyway. If we
     294             :     // cache it, we'll have to compute mPatternMatrix, which is annoying.
     295           0 :     return pattern.forget();
     296             :   case eStyleSVGPaintType_ContextStroke:
     297             :     pattern =
     298           0 :       mPaintDefinition.mContextPaint->GetStrokePattern(aDrawTarget,
     299             :                                                        aOpacity, aCTM,
     300           0 :                                                        aImgParams);
     301             :     // Don't cache this. mContextPaint will have cached it anyway. If we
     302             :     // cache it, we'll have to compute mPatternMatrix, which is annoying.
     303           0 :     return pattern.forget();
     304             :   default:
     305           0 :     MOZ_ASSERT(false, "invalid paint type");
     306             :     return nullptr;
     307             :   }
     308             : 
     309           0 :   mPatternCache.Put(aOpacity, pattern);
     310           0 :   return pattern.forget();
     311             : }
     312             : 
     313          13 : AutoSetRestoreSVGContextPaint::AutoSetRestoreSVGContextPaint(
     314             :                                  const SVGContextPaint* aContextPaint,
     315          13 :                                  nsIDocument* aSVGDocument)
     316             :   : mSVGDocument(aSVGDocument)
     317          13 :   , mOuterContextPaint(aSVGDocument->GetProperty(nsGkAtoms::svgContextPaint))
     318             : {
     319             :   // The way that we supply context paint is to temporarily set the context
     320             :   // paint on the owner document of the SVG that we're painting while it's
     321             :   // being painted.
     322             : 
     323          13 :   MOZ_ASSERT(aContextPaint);
     324          13 :   MOZ_ASSERT(aSVGDocument->IsBeingUsedAsImage(),
     325             :              "SVGContextPaint::GetContextPaint assumes this");
     326             : 
     327          13 :   if (mOuterContextPaint) {
     328           0 :     mSVGDocument->UnsetProperty(nsGkAtoms::svgContextPaint);
     329             :   }
     330             : 
     331             :   DebugOnly<nsresult> res =
     332          26 :     mSVGDocument->SetProperty(nsGkAtoms::svgContextPaint,
     333          26 :                               const_cast<SVGContextPaint*>(aContextPaint));
     334             : 
     335          13 :   NS_WARNING_ASSERTION(NS_SUCCEEDED(res), "Failed to set context paint");
     336          13 : }
     337             : 
     338          26 : AutoSetRestoreSVGContextPaint::~AutoSetRestoreSVGContextPaint()
     339             : {
     340          13 :   mSVGDocument->UnsetProperty(nsGkAtoms::svgContextPaint);
     341          13 :   if (mOuterContextPaint) {
     342             :     DebugOnly<nsresult> res =
     343           0 :       mSVGDocument->SetProperty(nsGkAtoms::svgContextPaint, mOuterContextPaint);
     344             : 
     345           0 :     NS_WARNING_ASSERTION(NS_SUCCEEDED(res), "Failed to restore context paint");
     346             :   }
     347          13 : }
     348             : 
     349             : 
     350             : // SVGEmbeddingContextPaint
     351             : 
     352             : already_AddRefed<gfxPattern>
     353          14 : SVGEmbeddingContextPaint::GetFillPattern(const DrawTarget* aDrawTarget,
     354             :                                          float aFillOpacity,
     355             :                                          const gfxMatrix& aCTM,
     356             :                                          imgDrawingParams& aImgParams)
     357             : {
     358          14 :   if (!mFill) {
     359           0 :     return nullptr;
     360             :   }
     361             :   // The gfxPattern that we create below depends on aFillOpacity, and since
     362             :   // different elements in the SVG image may pass in different values for
     363             :   // fill opacities we don't try to cache the gfxPattern that we create.
     364          14 :   Color fill = *mFill;
     365          14 :   fill.a *= aFillOpacity;
     366          14 :   return do_AddRef(new gfxPattern(fill));
     367             : }
     368             : 
     369             : already_AddRefed<gfxPattern>
     370           0 : SVGEmbeddingContextPaint::GetStrokePattern(const DrawTarget* aDrawTarget,
     371             :                                            float aStrokeOpacity,
     372             :                                            const gfxMatrix& aCTM,
     373             :                                            imgDrawingParams& aImgParams)
     374             : {
     375           0 :   if (!mStroke) {
     376           0 :     return nullptr;
     377             :   }
     378           0 :   Color stroke = *mStroke;
     379           0 :   stroke.a *= aStrokeOpacity;
     380           0 :   return do_AddRef(new gfxPattern(stroke));
     381             : }
     382             : 
     383             : uint32_t
     384          53 : SVGEmbeddingContextPaint::Hash() const
     385             : {
     386          53 :   uint32_t hash = 0;
     387             : 
     388          53 :   if (mFill) {
     389          53 :     hash = HashGeneric(hash, mFill->ToABGR());
     390             :   } else {
     391             :     // Arbitrary number, just to avoid trivial hash collisions between pairs of
     392             :     // instances where one embedding context has fill set to the same value as
     393             :     // another context has stroke set to.
     394           0 :     hash = 1;
     395             :   }
     396             : 
     397          53 :   if (mStroke) {
     398           0 :     hash = HashGeneric(hash, mStroke->ToABGR());
     399             :   }
     400             : 
     401          53 :   if (mFillOpacity != 1.0f) {
     402           7 :     hash = HashGeneric(hash, mFillOpacity);
     403             :   }
     404             : 
     405          53 :   if (mStrokeOpacity != 1.0f) {
     406           0 :     hash = HashGeneric(hash, mStrokeOpacity);
     407             :   }
     408             : 
     409          53 :   return hash;
     410             : }
     411             : 
     412             : } // namespace mozilla

Generated by: LCOV version 1.13