LCOV - code coverage report
Current view: top level - layout/generic - nsHTMLCanvasFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 190 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 31 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; 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             : /* rendering object for the HTML <canvas> element */
       7             : 
       8             : #include "nsHTMLCanvasFrame.h"
       9             : 
      10             : #include "nsGkAtoms.h"
      11             : #include "mozilla/Assertions.h"
      12             : #include "mozilla/dom/HTMLCanvasElement.h"
      13             : #include "nsDisplayList.h"
      14             : #include "nsLayoutUtils.h"
      15             : #include "nsStyleUtil.h"
      16             : #include "ImageLayers.h"
      17             : #include "Layers.h"
      18             : #include "ActiveLayerTracker.h"
      19             : 
      20             : #include <algorithm>
      21             : 
      22             : using namespace mozilla;
      23             : using namespace mozilla::dom;
      24             : using namespace mozilla::layers;
      25             : using namespace mozilla::gfx;
      26             : 
      27             : /* Helper for our nsIFrame::GetIntrinsicSize() impl. Takes the result of
      28             :  * "GetCanvasSize()" as a parameter, which may help avoid redundant
      29             :  * indirect calls to GetCanvasSize().
      30             :  *
      31             :  * @param aCanvasSizeInPx The canvas's size in CSS pixels, as returned
      32             :  *                        by GetCanvasSize().
      33             :  * @return The canvas's intrinsic size, as an IntrinsicSize object.
      34             :  */
      35             : static IntrinsicSize
      36           0 : IntrinsicSizeFromCanvasSize(const nsIntSize& aCanvasSizeInPx)
      37             : {
      38           0 :   IntrinsicSize intrinsicSize;
      39           0 :   intrinsicSize.width.SetCoordValue(
      40           0 :     nsPresContext::CSSPixelsToAppUnits(aCanvasSizeInPx.width));
      41           0 :   intrinsicSize.height.SetCoordValue(
      42           0 :     nsPresContext::CSSPixelsToAppUnits(aCanvasSizeInPx.height));
      43             : 
      44           0 :   return intrinsicSize;
      45             : }
      46             : 
      47             : /* Helper for our nsIFrame::GetIntrinsicRatio() impl. Takes the result of
      48             :  * "GetCanvasSize()" as a parameter, which may help avoid redundant
      49             :  * indirect calls to GetCanvasSize().
      50             :  *
      51             :  * @param aCanvasSizeInPx The canvas's size in CSS pixels, as returned
      52             :  *                        by GetCanvasSize().
      53             :  * @return The canvas's intrinsic ratio, as a nsSize.
      54             :  */
      55             : static nsSize
      56           0 : IntrinsicRatioFromCanvasSize(const nsIntSize& aCanvasSizeInPx)
      57             : {
      58           0 :   return nsSize(nsPresContext::CSSPixelsToAppUnits(aCanvasSizeInPx.width),
      59           0 :                 nsPresContext::CSSPixelsToAppUnits(aCanvasSizeInPx.height));
      60             : }
      61             : 
      62             : class nsDisplayCanvas : public nsDisplayItem {
      63             : public:
      64           0 :   nsDisplayCanvas(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
      65           0 :     : nsDisplayItem(aBuilder, aFrame)
      66             :   {
      67           0 :     MOZ_COUNT_CTOR(nsDisplayCanvas);
      68           0 :   }
      69             : #ifdef NS_BUILD_REFCNT_LOGGING
      70           0 :   virtual ~nsDisplayCanvas() {
      71           0 :     MOZ_COUNT_DTOR(nsDisplayCanvas);
      72           0 :   }
      73             : #endif
      74             : 
      75           0 :   NS_DISPLAY_DECL_NAME("nsDisplayCanvas", TYPE_CANVAS)
      76             : 
      77           0 :   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
      78             :                                    bool* aSnap) override {
      79           0 :     *aSnap = false;
      80           0 :     nsHTMLCanvasFrame* f = static_cast<nsHTMLCanvasFrame*>(Frame());
      81             :     HTMLCanvasElement* canvas =
      82           0 :       HTMLCanvasElement::FromContent(f->GetContent());
      83           0 :     nsRegion result;
      84           0 :     if (canvas->GetIsOpaque()) {
      85             :       // OK, the entire region painted by the canvas is opaque. But what is
      86             :       // that region? It's the canvas's "dest rect" (controlled by the
      87             :       // object-fit/object-position CSS properties), clipped to the container's
      88             :       // content box (which is what GetBounds() returns). So, we grab those
      89             :       // rects and intersect them.
      90           0 :       nsRect constraintRect = GetBounds(aBuilder, aSnap);
      91             : 
      92             :       // Need intrinsic size & ratio, for ComputeObjectDestRect:
      93           0 :       nsIntSize canvasSize = f->GetCanvasSize();
      94           0 :       IntrinsicSize intrinsicSize = IntrinsicSizeFromCanvasSize(canvasSize);
      95           0 :       nsSize intrinsicRatio = IntrinsicRatioFromCanvasSize(canvasSize);
      96             : 
      97             :       const nsRect destRect =
      98             :         nsLayoutUtils::ComputeObjectDestRect(constraintRect,
      99             :                                              intrinsicSize, intrinsicRatio,
     100           0 :                                              f->StylePosition());
     101           0 :       return nsRegion(destRect.Intersect(constraintRect));
     102             :     }
     103           0 :     return result;
     104             :   }
     105             : 
     106           0 :   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
     107             :                            bool* aSnap) override {
     108           0 :     *aSnap = true;
     109           0 :     nsHTMLCanvasFrame* f = static_cast<nsHTMLCanvasFrame*>(Frame());
     110           0 :     return f->GetInnerArea() + ToReferenceFrame();
     111             :   }
     112             : 
     113           0 :   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
     114             :                                              LayerManager* aManager,
     115             :                                              const ContainerLayerParameters& aContainerParameters) override
     116             :   {
     117           0 :     return static_cast<nsHTMLCanvasFrame*>(mFrame)->
     118           0 :       BuildLayer(aBuilder, aManager, this, aContainerParameters);
     119             :   }
     120           0 :   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
     121             :                                    LayerManager* aManager,
     122             :                                    const ContainerLayerParameters& aParameters) override
     123             :   {
     124           0 :     if (HTMLCanvasElement::FromContent(mFrame->GetContent())->ShouldForceInactiveLayer(aManager))
     125           0 :       return LAYER_INACTIVE;
     126             : 
     127             :     // If compositing is cheap, just do that
     128           0 :     if (aManager->IsCompositingCheap() ||
     129           0 :         ActiveLayerTracker::IsContentActive(mFrame))
     130           0 :       return mozilla::LAYER_ACTIVE;
     131             : 
     132           0 :     return LAYER_INACTIVE;
     133             :   }
     134             : };
     135             : 
     136             : 
     137             : nsIFrame*
     138           0 : NS_NewHTMLCanvasFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
     139             : {
     140           0 :   return new (aPresShell) nsHTMLCanvasFrame(aContext);
     141             : }
     142             : 
     143           0 : NS_QUERYFRAME_HEAD(nsHTMLCanvasFrame)
     144           0 :   NS_QUERYFRAME_ENTRY(nsHTMLCanvasFrame)
     145           0 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
     146             : 
     147           0 : NS_IMPL_FRAMEARENA_HELPERS(nsHTMLCanvasFrame)
     148             : 
     149             : void
     150           0 : nsHTMLCanvasFrame::Init(nsIContent*       aContent,
     151             :                         nsContainerFrame* aParent,
     152             :                         nsIFrame*         aPrevInFlow)
     153             : {
     154           0 :   nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
     155             : 
     156             :   // We can fill in the canvas before the canvas frame is created, in
     157             :   // which case we never get around to marking the content as active. Therefore,
     158             :   // we mark it active here when we create the frame.
     159           0 :   ActiveLayerTracker::NotifyContentChange(this);
     160           0 : }
     161             : 
     162           0 : nsHTMLCanvasFrame::~nsHTMLCanvasFrame()
     163             : {
     164           0 : }
     165             : 
     166             : nsIntSize
     167           0 : nsHTMLCanvasFrame::GetCanvasSize()
     168             : {
     169           0 :   nsIntSize size(0,0);
     170             :   HTMLCanvasElement *canvas =
     171           0 :     HTMLCanvasElement::FromContentOrNull(GetContent());
     172           0 :   if (canvas) {
     173           0 :     size = canvas->GetSize();
     174           0 :     MOZ_ASSERT(size.width >= 0 && size.height >= 0,
     175             :                "we should've required <canvas> width/height attrs to be "
     176             :                "unsigned (non-negative) values");
     177             :   } else {
     178           0 :     NS_NOTREACHED("couldn't get canvas size");
     179             :   }
     180             : 
     181           0 :   return size;
     182             : }
     183             : 
     184             : /* virtual */ nscoord
     185           0 : nsHTMLCanvasFrame::GetMinISize(gfxContext *aRenderingContext)
     186             : {
     187             :   // XXX The caller doesn't account for constraints of the height,
     188             :   // min-height, and max-height properties.
     189           0 :   bool vertical = GetWritingMode().IsVertical();
     190           0 :   nscoord result = nsPresContext::CSSPixelsToAppUnits(
     191           0 :     vertical ? GetCanvasSize().height : GetCanvasSize().width);
     192           0 :   DISPLAY_MIN_WIDTH(this, result);
     193           0 :   return result;
     194             : }
     195             : 
     196             : /* virtual */ nscoord
     197           0 : nsHTMLCanvasFrame::GetPrefISize(gfxContext *aRenderingContext)
     198             : {
     199             :   // XXX The caller doesn't account for constraints of the height,
     200             :   // min-height, and max-height properties.
     201           0 :   bool vertical = GetWritingMode().IsVertical();
     202           0 :   nscoord result = nsPresContext::CSSPixelsToAppUnits(
     203           0 :     vertical ? GetCanvasSize().height : GetCanvasSize().width);
     204           0 :   DISPLAY_PREF_WIDTH(this, result);
     205           0 :   return result;
     206             : }
     207             : 
     208             : /* virtual */ IntrinsicSize
     209           0 : nsHTMLCanvasFrame::GetIntrinsicSize()
     210             : {
     211           0 :   return IntrinsicSizeFromCanvasSize(GetCanvasSize());
     212             : }
     213             : 
     214             : /* virtual */ nsSize
     215           0 : nsHTMLCanvasFrame::GetIntrinsicRatio()
     216             : {
     217           0 :   return IntrinsicRatioFromCanvasSize(GetCanvasSize());
     218             : }
     219             : 
     220             : /* virtual */
     221             : LogicalSize
     222           0 : nsHTMLCanvasFrame::ComputeSize(gfxContext *aRenderingContext,
     223             :                                WritingMode aWM,
     224             :                                const LogicalSize& aCBSize,
     225             :                                nscoord aAvailableISize,
     226             :                                const LogicalSize& aMargin,
     227             :                                const LogicalSize& aBorder,
     228             :                                const LogicalSize& aPadding,
     229             :                                ComputeSizeFlags aFlags)
     230             : {
     231           0 :   nsIntSize size = GetCanvasSize();
     232             : 
     233           0 :   IntrinsicSize intrinsicSize;
     234           0 :   intrinsicSize.width.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(size.width));
     235           0 :   intrinsicSize.height.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(size.height));
     236             : 
     237           0 :   nsSize intrinsicRatio = GetIntrinsicRatio(); // won't actually be used
     238             : 
     239             :   return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
     240             :                                             intrinsicSize, intrinsicRatio,
     241             :                                             aCBSize, aMargin, aBorder, aPadding,
     242           0 :                                             aFlags);
     243             : }
     244             : 
     245             : void
     246           0 : nsHTMLCanvasFrame::Reflow(nsPresContext*           aPresContext,
     247             :                           ReflowOutput&     aMetrics,
     248             :                           const ReflowInput& aReflowInput,
     249             :                           nsReflowStatus&          aStatus)
     250             : {
     251           0 :   MarkInReflow();
     252           0 :   DO_GLOBAL_REFLOW_COUNT("nsHTMLCanvasFrame");
     253           0 :   DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
     254           0 :   NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
     255             :                   ("enter nsHTMLCanvasFrame::Reflow: availSize=%d,%d",
     256             :                   aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight()));
     257             : 
     258           0 :   NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow");
     259             : 
     260           0 :   aStatus.Reset();
     261             : 
     262           0 :   WritingMode wm = aReflowInput.GetWritingMode();
     263             :   LogicalSize finalSize(wm,
     264             :                         aReflowInput.ComputedISize(),
     265           0 :                         aReflowInput.ComputedBSize());
     266             : 
     267             :   // stash this away so we can compute our inner area later
     268           0 :   mBorderPadding   = aReflowInput.ComputedLogicalBorderPadding();
     269             : 
     270           0 :   finalSize.ISize(wm) += mBorderPadding.IStartEnd(wm);
     271           0 :   finalSize.BSize(wm) += mBorderPadding.BStartEnd(wm);
     272             : 
     273           0 :   if (GetPrevInFlow()) {
     274           0 :     nscoord y = GetContinuationOffset(&finalSize.ISize(wm));
     275           0 :     finalSize.BSize(wm) -= y + mBorderPadding.BStart(wm);
     276           0 :     finalSize.BSize(wm) = std::max(0, finalSize.BSize(wm));
     277             :   }
     278             : 
     279           0 :   aMetrics.SetSize(wm, finalSize);
     280           0 :   aMetrics.SetOverflowAreasToDesiredBounds();
     281           0 :   FinishAndStoreOverflow(&aMetrics);
     282             : 
     283             :   // Reflow the single anon block child.
     284           0 :   nsReflowStatus childStatus;
     285           0 :   nsIFrame* childFrame = mFrames.FirstChild();
     286           0 :   WritingMode childWM = childFrame->GetWritingMode();
     287           0 :   LogicalSize availSize = aReflowInput.ComputedSize(childWM);
     288           0 :   availSize.BSize(childWM) = NS_UNCONSTRAINEDSIZE;
     289           0 :   NS_ASSERTION(!childFrame->GetNextSibling(), "HTML canvas should have 1 kid");
     290           0 :   ReflowOutput childDesiredSize(aReflowInput.GetWritingMode(), aMetrics.mFlags);
     291             :   ReflowInput childReflowInput(aPresContext, aReflowInput, childFrame,
     292           0 :                                      availSize);
     293           0 :   ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowInput,
     294           0 :               0, 0, 0, childStatus, nullptr);
     295             :   FinishReflowChild(childFrame, aPresContext, childDesiredSize,
     296           0 :                     &childReflowInput, 0, 0, 0);
     297             : 
     298           0 :   NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
     299             :                   ("exit nsHTMLCanvasFrame::Reflow: size=%d,%d",
     300             :                    aMetrics.ISize(wm), aMetrics.BSize(wm)));
     301           0 :   NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aMetrics);
     302           0 : }
     303             : 
     304             : // FIXME taken from nsImageFrame, but then had splittable frame stuff
     305             : // removed.  That needs to be fixed.
     306             : // XXXdholbert As in nsImageFrame, this function's clients should probably
     307             : // just be calling GetContentRectRelativeToSelf().
     308             : nsRect
     309           0 : nsHTMLCanvasFrame::GetInnerArea() const
     310             : {
     311           0 :   nsMargin bp = mBorderPadding.GetPhysicalMargin(GetWritingMode());
     312           0 :   nsRect r;
     313           0 :   r.x = bp.left;
     314           0 :   r.y = bp.top;
     315           0 :   r.width = mRect.width - bp.left - bp.right;
     316           0 :   r.height = mRect.height - bp.top - bp.bottom;
     317           0 :   return r;
     318             : }
     319             : 
     320             : already_AddRefed<Layer>
     321           0 : nsHTMLCanvasFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
     322             :                               LayerManager* aManager,
     323             :                               nsDisplayItem* aItem,
     324             :                               const ContainerLayerParameters& aContainerParameters)
     325             : {
     326           0 :   nsRect area = GetContentRectRelativeToSelf() + aItem->ToReferenceFrame();
     327           0 :   HTMLCanvasElement* element = static_cast<HTMLCanvasElement*>(GetContent());
     328           0 :   nsIntSize canvasSizeInPx = GetCanvasSize();
     329             : 
     330           0 :   nsPresContext* presContext = PresContext();
     331           0 :   element->HandlePrintCallback(presContext->Type());
     332             : 
     333           0 :   if (canvasSizeInPx.width <= 0 || canvasSizeInPx.height <= 0 || area.IsEmpty())
     334           0 :     return nullptr;
     335             : 
     336             :   CanvasLayer* oldLayer = static_cast<CanvasLayer*>
     337           0 :     (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem));
     338           0 :   RefPtr<Layer> layer = element->GetCanvasLayer(aBuilder, oldLayer, aManager);
     339           0 :   if (!layer)
     340           0 :     return nullptr;
     341             : 
     342           0 :   IntrinsicSize intrinsicSize = IntrinsicSizeFromCanvasSize(canvasSizeInPx);
     343           0 :   nsSize intrinsicRatio = IntrinsicRatioFromCanvasSize(canvasSizeInPx);
     344             : 
     345             :   nsRect dest =
     346             :     nsLayoutUtils::ComputeObjectDestRect(area, intrinsicSize, intrinsicRatio,
     347           0 :                                          StylePosition());
     348             : 
     349           0 :   gfxRect destGFXRect = presContext->AppUnitsToGfxUnits(dest);
     350             : 
     351             :   // Transform the canvas into the right place
     352           0 :   gfxPoint p = destGFXRect.TopLeft() + aContainerParameters.mOffset;
     353           0 :   Matrix transform = Matrix::Translation(p.x, p.y);
     354           0 :   transform.PreScale(destGFXRect.Width() / canvasSizeInPx.width,
     355           0 :                      destGFXRect.Height() / canvasSizeInPx.height);
     356           0 :   layer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
     357           0 :   if (layer->GetType() == layers::Layer::TYPE_CANVAS) {
     358           0 :     RefPtr<CanvasLayer> canvasLayer = static_cast<CanvasLayer*>(layer.get());
     359           0 :     canvasLayer->SetSamplingFilter(nsLayoutUtils::GetSamplingFilterForFrame(this));
     360           0 :   } else if (layer->GetType() == layers::Layer::TYPE_IMAGE) {
     361           0 :     RefPtr<ImageLayer> imageLayer = static_cast<ImageLayer*>(layer.get());
     362           0 :     imageLayer->SetSamplingFilter(nsLayoutUtils::GetSamplingFilterForFrame(this));
     363             :   }
     364             : 
     365           0 :   return layer.forget();
     366             : }
     367             : 
     368             : void
     369           0 : nsHTMLCanvasFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
     370             :                                     const nsRect&           aDirtyRect,
     371             :                                     const nsDisplayListSet& aLists)
     372             : {
     373           0 :   if (!IsVisibleForPainting(aBuilder))
     374           0 :     return;
     375             : 
     376           0 :   DisplayBorderBackgroundOutline(aBuilder, aLists);
     377             : 
     378             :   uint32_t clipFlags =
     379           0 :     nsStyleUtil::ObjectPropsMightCauseOverflow(StylePosition()) ?
     380           0 :     0 : DisplayListClipState::ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT;
     381             : 
     382             :   DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox
     383           0 :     clip(aBuilder, this, clipFlags);
     384             : 
     385           0 :   aLists.Content()->AppendNewToTop(
     386           0 :     new (aBuilder) nsDisplayCanvas(aBuilder, this));
     387             : 
     388           0 :   DisplaySelectionOverlay(aBuilder, aLists.Content(),
     389           0 :                           nsISelectionDisplay::DISPLAY_IMAGES);
     390             : }
     391             : 
     392             : // get the offset into the content area of the image where aImg starts if it is a continuation.
     393             : // from nsImageFrame
     394             : nscoord
     395           0 : nsHTMLCanvasFrame::GetContinuationOffset(nscoord* aWidth) const
     396             : {
     397           0 :   nscoord offset = 0;
     398           0 :   if (aWidth) {
     399           0 :     *aWidth = 0;
     400             :   }
     401             : 
     402           0 :   if (GetPrevInFlow()) {
     403           0 :     for (nsIFrame* prevInFlow = GetPrevInFlow() ; prevInFlow; prevInFlow = prevInFlow->GetPrevInFlow()) {
     404           0 :       nsRect rect = prevInFlow->GetRect();
     405           0 :       if (aWidth) {
     406           0 :         *aWidth = rect.width;
     407             :       }
     408           0 :       offset += rect.height;
     409             :     }
     410           0 :     offset -= mBorderPadding.GetPhysicalMargin(GetWritingMode()).top;
     411           0 :     offset = std::max(0, offset);
     412             :   }
     413           0 :   return offset;
     414             : }
     415             : 
     416             : void
     417           0 : nsHTMLCanvasFrame::AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult)
     418             : {
     419           0 :   MOZ_ASSERT(mFrames.FirstChild(), "Must have our canvas content anon box");
     420           0 :   MOZ_ASSERT(!mFrames.FirstChild()->GetNextSibling(),
     421             :              "Must only have our canvas content anon box");
     422           0 :   aResult.AppendElement(OwnedAnonBox(mFrames.FirstChild()));
     423           0 : }
     424             : 
     425             : #ifdef ACCESSIBILITY
     426             : a11y::AccType
     427           0 : nsHTMLCanvasFrame::AccessibleType()
     428             : {
     429           0 :   return a11y::eHTMLCanvasType;
     430             : }
     431             : #endif
     432             : 
     433             : #ifdef DEBUG_FRAME_DUMP
     434             : nsresult
     435           0 : nsHTMLCanvasFrame::GetFrameName(nsAString& aResult) const
     436             : {
     437           0 :   return MakeFrameName(NS_LITERAL_STRING("HTMLCanvas"), aResult);
     438             : }
     439             : #endif
     440             : 

Generated by: LCOV version 1.13