LCOV - code coverage report
Current view: top level - layout/base - GeometryUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 185 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 17 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             : #include "GeometryUtils.h"
       7             : 
       8             : #include "mozilla/dom/DOMPointBinding.h"
       9             : #include "mozilla/dom/GeometryUtilsBinding.h"
      10             : #include "mozilla/dom/Element.h"
      11             : #include "mozilla/dom/Text.h"
      12             : #include "mozilla/dom/DOMPoint.h"
      13             : #include "mozilla/dom/DOMQuad.h"
      14             : #include "mozilla/dom/DOMRect.h"
      15             : #include "nsContentUtils.h"
      16             : #include "nsIFrame.h"
      17             : #include "nsGenericDOMDataNode.h"
      18             : #include "nsCSSFrameConstructor.h"
      19             : #include "nsLayoutUtils.h"
      20             : #include "nsSVGUtils.h"
      21             : 
      22             : using namespace mozilla;
      23             : using namespace mozilla::dom;
      24             : 
      25             : namespace mozilla {
      26             : 
      27             : enum GeometryNodeType {
      28             :   GEOMETRY_NODE_ELEMENT,
      29             :   GEOMETRY_NODE_TEXT,
      30             :   GEOMETRY_NODE_DOCUMENT
      31             : };
      32             : 
      33             : static nsIFrame*
      34           0 : GetFrameForNode(nsINode* aNode, GeometryNodeType aType)
      35             : {
      36           0 :   nsIDocument* doc = aNode->OwnerDoc();
      37           0 :   doc->FlushPendingNotifications(FlushType::Layout);
      38           0 :   switch (aType) {
      39             :   case GEOMETRY_NODE_ELEMENT:
      40           0 :     return aNode->AsContent()->GetPrimaryFrame();
      41             :   case GEOMETRY_NODE_TEXT: {
      42           0 :     nsIPresShell* presShell = doc->GetShell();
      43           0 :     if (presShell) {
      44           0 :       return presShell->FrameConstructor()->EnsureFrameForTextNode(
      45           0 :           static_cast<nsGenericDOMDataNode*>(aNode));
      46             :     }
      47           0 :     return nullptr;
      48             :   }
      49             :   case GEOMETRY_NODE_DOCUMENT: {
      50           0 :     nsIPresShell* presShell = doc->GetShell();
      51           0 :     return presShell ? presShell->GetRootFrame() : nullptr;
      52             :   }
      53             :   default:
      54           0 :     MOZ_ASSERT(false, "Unknown GeometryNodeType");
      55             :     return nullptr;
      56             :   }
      57             : }
      58             : 
      59             : static nsIFrame*
      60           0 : GetFrameForGeometryNode(const Optional<OwningGeometryNode>& aGeometryNode,
      61             :                         nsINode* aDefaultNode)
      62             : {
      63           0 :   if (!aGeometryNode.WasPassed()) {
      64           0 :     return GetFrameForNode(aDefaultNode->OwnerDoc(), GEOMETRY_NODE_DOCUMENT);
      65             :   }
      66             : 
      67           0 :   const OwningGeometryNode& value = aGeometryNode.Value();
      68           0 :   if (value.IsElement()) {
      69           0 :     return GetFrameForNode(value.GetAsElement(), GEOMETRY_NODE_ELEMENT);
      70             :   }
      71           0 :   if (value.IsDocument()) {
      72           0 :     return GetFrameForNode(value.GetAsDocument(), GEOMETRY_NODE_DOCUMENT);
      73             :   }
      74           0 :   return GetFrameForNode(value.GetAsText(), GEOMETRY_NODE_TEXT);
      75             : }
      76             : 
      77             : static nsIFrame*
      78           0 : GetFrameForGeometryNode(const GeometryNode& aGeometryNode)
      79             : {
      80           0 :   if (aGeometryNode.IsElement()) {
      81           0 :     return GetFrameForNode(&aGeometryNode.GetAsElement(), GEOMETRY_NODE_ELEMENT);
      82             :   }
      83           0 :   if (aGeometryNode.IsDocument()) {
      84           0 :     return GetFrameForNode(&aGeometryNode.GetAsDocument(), GEOMETRY_NODE_DOCUMENT);
      85             :   }
      86           0 :   return GetFrameForNode(&aGeometryNode.GetAsText(), GEOMETRY_NODE_TEXT);
      87             : }
      88             : 
      89             : static nsIFrame*
      90           0 : GetFrameForNode(nsINode* aNode)
      91             : {
      92           0 :   if (aNode->IsElement()) {
      93           0 :     return GetFrameForNode(aNode, GEOMETRY_NODE_ELEMENT);
      94             :   }
      95           0 :   if (aNode == aNode->OwnerDoc()) {
      96           0 :     return GetFrameForNode(aNode, GEOMETRY_NODE_DOCUMENT);
      97             :   }
      98           0 :   NS_ASSERTION(aNode->IsNodeOfType(nsINode::eTEXT), "Unknown node type");
      99           0 :   return GetFrameForNode(aNode, GEOMETRY_NODE_TEXT);
     100             : }
     101             : 
     102             : static nsIFrame*
     103           0 : GetFirstNonAnonymousFrameForGeometryNode(const Optional<OwningGeometryNode>& aNode,
     104             :                                          nsINode* aDefaultNode)
     105             : {
     106           0 :   nsIFrame* f = GetFrameForGeometryNode(aNode, aDefaultNode);
     107           0 :   if (f) {
     108           0 :     f = nsLayoutUtils::GetFirstNonAnonymousFrame(f);
     109             :   }
     110           0 :   return f;
     111             : }
     112             : 
     113             : static nsIFrame*
     114           0 : GetFirstNonAnonymousFrameForGeometryNode(const GeometryNode& aNode)
     115             : {
     116           0 :   nsIFrame* f = GetFrameForGeometryNode(aNode);
     117           0 :   if (f) {
     118           0 :     f = nsLayoutUtils::GetFirstNonAnonymousFrame(f);
     119             :   }
     120           0 :   return f;
     121             : }
     122             : 
     123             : static nsIFrame*
     124           0 : GetFirstNonAnonymousFrameForNode(nsINode* aNode)
     125             : {
     126           0 :   nsIFrame* f = GetFrameForNode(aNode);
     127           0 :   if (f) {
     128           0 :     f = nsLayoutUtils::GetFirstNonAnonymousFrame(f);
     129             :   }
     130           0 :   return f;
     131             : }
     132             : 
     133             : /**
     134             :  * This can modify aFrame to point to a different frame. This is needed to
     135             :  * handle SVG, where SVG elements can only compute a rect that's valid with
     136             :  * respect to the "outer SVG" frame.
     137             :  */
     138             : static nsRect
     139           0 : GetBoxRectForFrame(nsIFrame** aFrame, CSSBoxType aType)
     140             : {
     141           0 :   nsRect r;
     142           0 :   nsIFrame* f = nsSVGUtils::GetOuterSVGFrameAndCoveredRegion(*aFrame, &r);
     143           0 :   if (f && f != *aFrame) {
     144             :     // For non-outer SVG frames, the BoxType is ignored.
     145           0 :     *aFrame = f;
     146           0 :     return r;
     147             :   }
     148             : 
     149           0 :   f = *aFrame;
     150           0 :   switch (aType) {
     151           0 :   case CSSBoxType::Content: r = f->GetContentRectRelativeToSelf(); break;
     152           0 :   case CSSBoxType::Padding: r = f->GetPaddingRectRelativeToSelf(); break;
     153           0 :   case CSSBoxType::Border: r = nsRect(nsPoint(0, 0), f->GetSize()); break;
     154             :   case CSSBoxType::Margin: {
     155           0 :     r = nsRect(nsPoint(0, 0), f->GetSize());
     156           0 :     r.Inflate(f->GetUsedMargin());
     157           0 :     break;
     158             :   }
     159           0 :   default: MOZ_ASSERT(false, "unknown box type"); return r;
     160             :   }
     161             : 
     162           0 :   return r;
     163             : }
     164             : 
     165             : class AccumulateQuadCallback : public nsLayoutUtils::BoxCallback {
     166             : public:
     167           0 :   AccumulateQuadCallback(nsISupports* aParentObject,
     168             :                          nsTArray<RefPtr<DOMQuad> >& aResult,
     169             :                          nsIFrame* aRelativeToFrame,
     170             :                          const nsPoint& aRelativeToBoxTopLeft,
     171             :                          CSSBoxType aBoxType)
     172           0 :     : mParentObject(aParentObject)
     173             :     , mResult(aResult)
     174             :     , mRelativeToFrame(aRelativeToFrame)
     175             :     , mRelativeToBoxTopLeft(aRelativeToBoxTopLeft)
     176           0 :     , mBoxType(aBoxType)
     177             :   {
     178           0 :     if (mBoxType == CSSBoxType::Margin) {
     179             :       // Don't include the caption margin when computing margins for a
     180             :       // table
     181           0 :       mIncludeCaptionBoxForTable = false;
     182             :     }
     183           0 :   }
     184             : 
     185           0 :   virtual void AddBox(nsIFrame* aFrame) override
     186             :   {
     187           0 :     nsIFrame* f = aFrame;
     188           0 :     if (mBoxType == CSSBoxType::Margin && f->IsTableFrame()) {
     189             :       // Margin boxes for table frames should be taken from the table wrapper
     190             :       // frame, since that has the margin.
     191           0 :       f = f->GetParent();
     192             :     }
     193           0 :     nsRect box = GetBoxRectForFrame(&f, mBoxType);
     194             :     nsPoint appUnits[4] =
     195           0 :       { box.TopLeft(), box.TopRight(), box.BottomRight(), box.BottomLeft() };
     196           0 :     CSSPoint points[4];
     197           0 :     for (uint32_t i = 0; i < 4; ++i) {
     198           0 :       points[i] = CSSPoint(nsPresContext::AppUnitsToFloatCSSPixels(appUnits[i].x),
     199             :                            nsPresContext::AppUnitsToFloatCSSPixels(appUnits[i].y));
     200             :     }
     201             :     nsLayoutUtils::TransformResult rv =
     202           0 :       nsLayoutUtils::TransformPoints(f, mRelativeToFrame, 4, points);
     203           0 :     if (rv == nsLayoutUtils::TRANSFORM_SUCCEEDED) {
     204             :       CSSPoint delta(nsPresContext::AppUnitsToFloatCSSPixels(mRelativeToBoxTopLeft.x),
     205           0 :                      nsPresContext::AppUnitsToFloatCSSPixels(mRelativeToBoxTopLeft.y));
     206           0 :       for (uint32_t i = 0; i < 4; ++i) {
     207           0 :         points[i] -= delta;
     208             :       }
     209             :     } else {
     210           0 :       PodArrayZero(points);
     211             :     }
     212           0 :     mResult.AppendElement(new DOMQuad(mParentObject, points));
     213           0 :   }
     214             : 
     215             :   nsISupports* mParentObject;
     216             :   nsTArray<RefPtr<DOMQuad> >& mResult;
     217             :   nsIFrame* mRelativeToFrame;
     218             :   nsPoint mRelativeToBoxTopLeft;
     219             :   CSSBoxType mBoxType;
     220             : };
     221             : 
     222             : static nsPresContext*
     223           0 : FindTopLevelPresContext(nsPresContext* aPC)
     224             : {
     225           0 :   bool isChrome = aPC->IsChrome();
     226           0 :   nsPresContext* pc = aPC;
     227             :   for (;;) {
     228           0 :     nsPresContext* parent = pc->GetParentPresContext();
     229           0 :     if (!parent || parent->IsChrome() != isChrome) {
     230           0 :       return pc;
     231             :     }
     232           0 :     pc = parent;
     233           0 :   }
     234             : }
     235             : 
     236             : static bool
     237           0 : CheckFramesInSameTopLevelBrowsingContext(nsIFrame* aFrame1, nsIFrame* aFrame2,
     238             :                                          CallerType aCallerType)
     239             : {
     240           0 :   nsPresContext* pc1 = aFrame1->PresContext();
     241           0 :   nsPresContext* pc2 = aFrame2->PresContext();
     242           0 :   if (pc1 == pc2) {
     243           0 :     return true;
     244             :   }
     245           0 :   if (aCallerType == CallerType::System) {
     246           0 :     return true;
     247             :   }
     248           0 :   if (FindTopLevelPresContext(pc1) == FindTopLevelPresContext(pc2)) {
     249           0 :     return true;
     250             :   }
     251           0 :   return false;
     252             : }
     253             : 
     254           0 : void GetBoxQuads(nsINode* aNode,
     255             :                  const dom::BoxQuadOptions& aOptions,
     256             :                  nsTArray<RefPtr<DOMQuad> >& aResult,
     257             :                  CallerType aCallerType,
     258             :                  ErrorResult& aRv)
     259             : {
     260           0 :   nsIFrame* frame = GetFrameForNode(aNode);
     261           0 :   if (!frame) {
     262             :     // No boxes to return
     263           0 :     return;
     264             :   }
     265           0 :   AutoWeakFrame weakFrame(frame);
     266           0 :   nsIDocument* ownerDoc = aNode->OwnerDoc();
     267             :   nsIFrame* relativeToFrame =
     268           0 :     GetFirstNonAnonymousFrameForGeometryNode(aOptions.mRelativeTo, ownerDoc);
     269             :   // The first frame might be destroyed now if the above call lead to an
     270             :   // EnsureFrameForTextNode call.  We need to get the first frame again
     271             :   // when that happens and re-check it.
     272           0 :   if (!weakFrame.IsAlive()) {
     273           0 :     frame = GetFrameForNode(aNode);
     274           0 :     if (!frame) {
     275             :       // No boxes to return
     276           0 :       return;
     277             :     }
     278             :   }
     279           0 :   if (!relativeToFrame) {
     280           0 :     aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
     281           0 :     return;
     282             :   }
     283           0 :   if (!CheckFramesInSameTopLevelBrowsingContext(frame, relativeToFrame,
     284             :                                                 aCallerType)) {
     285           0 :     aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
     286           0 :     return;
     287             :   }
     288             :   // GetBoxRectForFrame can modify relativeToFrame so call it first.
     289             :   nsPoint relativeToTopLeft =
     290           0 :       GetBoxRectForFrame(&relativeToFrame, CSSBoxType::Border).TopLeft();
     291             :   AccumulateQuadCallback callback(ownerDoc, aResult, relativeToFrame,
     292           0 :                                   relativeToTopLeft, aOptions.mBox);
     293           0 :   nsLayoutUtils::GetAllInFlowBoxes(frame, &callback);
     294             : }
     295             : 
     296             : static void
     297           0 : TransformPoints(nsINode* aTo, const GeometryNode& aFrom,
     298             :                 uint32_t aPointCount, CSSPoint* aPoints,
     299             :                 const ConvertCoordinateOptions& aOptions,
     300             :                 CallerType aCallerType, ErrorResult& aRv)
     301             : {
     302           0 :   nsIFrame* fromFrame = GetFirstNonAnonymousFrameForGeometryNode(aFrom);
     303           0 :   AutoWeakFrame weakFrame(fromFrame);
     304           0 :   nsIFrame* toFrame = GetFirstNonAnonymousFrameForNode(aTo);
     305             :   // The first frame might be destroyed now if the above call lead to an
     306             :   // EnsureFrameForTextNode call.  We need to get the first frame again
     307             :   // when that happens.
     308           0 :   if (fromFrame && !weakFrame.IsAlive()) {
     309           0 :     fromFrame = GetFirstNonAnonymousFrameForGeometryNode(aFrom);
     310             :   }
     311           0 :   if (!fromFrame || !toFrame) {
     312           0 :     aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
     313           0 :     return;
     314             :   }
     315           0 :   if (!CheckFramesInSameTopLevelBrowsingContext(fromFrame, toFrame, aCallerType)) {
     316           0 :     aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
     317           0 :     return;
     318             :   }
     319             : 
     320           0 :   nsPoint fromOffset = GetBoxRectForFrame(&fromFrame, aOptions.mFromBox).TopLeft();
     321           0 :   nsPoint toOffset = GetBoxRectForFrame(&toFrame, aOptions.mToBox).TopLeft();
     322             :   CSSPoint fromOffsetGfx(nsPresContext::AppUnitsToFloatCSSPixels(fromOffset.x),
     323           0 :                          nsPresContext::AppUnitsToFloatCSSPixels(fromOffset.y));
     324           0 :   for (uint32_t i = 0; i < aPointCount; ++i) {
     325           0 :     aPoints[i] += fromOffsetGfx;
     326             :   }
     327             :   nsLayoutUtils::TransformResult rv =
     328           0 :     nsLayoutUtils::TransformPoints(fromFrame, toFrame, aPointCount, aPoints);
     329           0 :   if (rv == nsLayoutUtils::TRANSFORM_SUCCEEDED) {
     330             :     CSSPoint toOffsetGfx(nsPresContext::AppUnitsToFloatCSSPixels(toOffset.x),
     331           0 :                          nsPresContext::AppUnitsToFloatCSSPixels(toOffset.y));
     332           0 :     for (uint32_t i = 0; i < aPointCount; ++i) {
     333           0 :       aPoints[i] -= toOffsetGfx;
     334             :     }
     335             :   } else {
     336           0 :     PodZero(aPoints, aPointCount);
     337             :   }
     338             : }
     339             : 
     340             : already_AddRefed<DOMQuad>
     341           0 : ConvertQuadFromNode(nsINode* aTo, dom::DOMQuad& aQuad,
     342             :                     const GeometryNode& aFrom,
     343             :                     const dom::ConvertCoordinateOptions& aOptions,
     344             :                     CallerType aCallerType,
     345             :                     ErrorResult& aRv)
     346             : {
     347           0 :   CSSPoint points[4];
     348           0 :   for (uint32_t i = 0; i < 4; ++i) {
     349           0 :     DOMPoint* p = aQuad.Point(i);
     350           0 :     if (p->W() != 1.0 || p->Z() != 0.0) {
     351           0 :       aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     352           0 :       return nullptr;
     353             :     }
     354           0 :     points[i] = CSSPoint(p->X(), p->Y());
     355             :   }
     356           0 :   TransformPoints(aTo, aFrom, 4, points, aOptions, aCallerType, aRv);
     357           0 :   if (aRv.Failed()) {
     358           0 :     return nullptr;
     359             :   }
     360           0 :   RefPtr<DOMQuad> result = new DOMQuad(aTo->GetParentObject().mObject, points);
     361           0 :   return result.forget();
     362             : }
     363             : 
     364             : already_AddRefed<DOMQuad>
     365           0 : ConvertRectFromNode(nsINode* aTo, dom::DOMRectReadOnly& aRect,
     366             :                     const GeometryNode& aFrom,
     367             :                     const dom::ConvertCoordinateOptions& aOptions,
     368             :                     CallerType aCallerType,
     369             :                     ErrorResult& aRv)
     370             : {
     371           0 :   CSSPoint points[4];
     372           0 :   double x = aRect.X(), y = aRect.Y(), w = aRect.Width(), h = aRect.Height();
     373           0 :   points[0] = CSSPoint(x, y);
     374           0 :   points[1] = CSSPoint(x + w, y);
     375           0 :   points[2] = CSSPoint(x + w, y + h);
     376           0 :   points[3] = CSSPoint(x, y + h);
     377           0 :   TransformPoints(aTo, aFrom, 4, points, aOptions, aCallerType, aRv);
     378           0 :   if (aRv.Failed()) {
     379           0 :     return nullptr;
     380             :   }
     381           0 :   RefPtr<DOMQuad> result = new DOMQuad(aTo->GetParentObject().mObject, points);
     382           0 :   return result.forget();
     383             : }
     384             : 
     385             : already_AddRefed<DOMPoint>
     386           0 : ConvertPointFromNode(nsINode* aTo, const dom::DOMPointInit& aPoint,
     387             :                      const GeometryNode& aFrom,
     388             :                      const dom::ConvertCoordinateOptions& aOptions,
     389             :                      CallerType aCallerType,
     390             :                      ErrorResult& aRv)
     391             : {
     392           0 :   if (aPoint.mW != 1.0 || aPoint.mZ != 0.0) {
     393           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     394           0 :     return nullptr;
     395             :   }
     396           0 :   CSSPoint point(aPoint.mX, aPoint.mY);
     397           0 :   TransformPoints(aTo, aFrom, 1, &point, aOptions, aCallerType, aRv);
     398           0 :   if (aRv.Failed()) {
     399           0 :     return nullptr;
     400             :   }
     401           0 :   RefPtr<DOMPoint> result = new DOMPoint(aTo->GetParentObject().mObject, point.x, point.y);
     402           0 :   return result.forget();
     403             : }
     404             : 
     405             : } // namespace mozilla

Generated by: LCOV version 1.13