Bug 917755. Part 5: Implement GeometryUtils GetBoxQuads. r=matspal
☠☠ backed out by b7bb4f7697c3 ☠ ☠
authorRobert O'Callahan <robert@ocallahan.org>
Wed, 12 Mar 2014 09:11:38 +0800
changeset 174244 4771c2b309ad3389e96de6960e5eb315fb4e0a06
parent 174243 8ad57cf09e758617455a8aebdc33867bb10093ba
child 174245 896bfaeab866026e8499e015cf53edd010a8aff5
push id41230
push userrocallahan@mozilla.com
push dateWed, 19 Mar 2014 06:26:26 +0000
treeherdermozilla-inbound@2f3187619c9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmatspal
bugs917755
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 917755. Part 5: Implement GeometryUtils GetBoxQuads. r=matspal
layout/base/GeometryUtils.cpp
layout/base/GeometryUtils.h
layout/base/moz.build
new file mode 100644
--- /dev/null
+++ b/layout/base/GeometryUtils.cpp
@@ -0,0 +1,238 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GeometryUtils.h"
+
+#include "mozilla/dom/GeometryUtilsBinding.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/Text.h"
+#include "mozilla/dom/DOMQuad.h"
+#include "nsIFrame.h"
+#include "nsGenericDOMDataNode.h"
+#include "nsCSSFrameConstructor.h"
+#include "nsLayoutUtils.h"
+#include "nsSVGUtils.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+namespace mozilla {
+
+typedef OwningTextOrElementOrDocument GeometryNode;
+
+enum GeometryNodeType {
+  GEOMETRY_NODE_ELEMENT,
+  GEOMETRY_NODE_TEXT,
+  GEOMETRY_NODE_DOCUMENT
+};
+
+static nsIFrame*
+GetFrameForNode(nsINode* aNode, GeometryNodeType aType)
+{
+  nsIDocument* doc = aNode->OwnerDoc();
+  doc->FlushPendingNotifications(Flush_Layout);
+  switch (aType) {
+  case GEOMETRY_NODE_ELEMENT:
+    return aNode->AsContent()->GetPrimaryFrame();
+  case GEOMETRY_NODE_TEXT: {
+    nsIPresShell* presShell = doc->GetShell();
+    if (presShell) {
+      return presShell->FrameConstructor()->EnsureFrameForTextNode(
+          static_cast<nsGenericDOMDataNode*>(aNode));
+    }
+    return nullptr;
+  }
+  case GEOMETRY_NODE_DOCUMENT: {
+    nsIPresShell* presShell = doc->GetShell();
+    return presShell ? presShell->GetRootFrame() : nullptr;
+  }
+  default:
+    MOZ_ASSERT(false, "Unknown GeometryNodeType");
+    return nullptr;
+  }
+}
+
+static nsIFrame*
+GetFrameForGeometryNode(const Optional<GeometryNode>& aGeometryNode,
+                        nsINode* aDefaultNode)
+{
+  if (!aGeometryNode.WasPassed()) {
+    return GetFrameForNode(aDefaultNode->OwnerDoc(), GEOMETRY_NODE_DOCUMENT);
+  }
+
+  const GeometryNode& value = aGeometryNode.Value();
+  if (value.IsElement()) {
+    return GetFrameForNode(value.GetAsElement(), GEOMETRY_NODE_ELEMENT);
+  }
+  if (value.IsDocument()) {
+    return GetFrameForNode(value.GetAsDocument(), GEOMETRY_NODE_DOCUMENT);
+  }
+  return GetFrameForNode(value.GetAsText(), GEOMETRY_NODE_TEXT);
+}
+
+static nsIFrame*
+GetFrameForNode(nsINode* aNode)
+{
+  if (aNode->IsElement()) {
+    return GetFrameForNode(aNode, GEOMETRY_NODE_ELEMENT);
+  }
+  if (aNode == aNode->OwnerDoc()) {
+    return GetFrameForNode(aNode, GEOMETRY_NODE_DOCUMENT);
+  }
+  NS_ASSERTION(aNode->IsNodeOfType(nsINode::eTEXT), "Unknown node type");
+  return GetFrameForNode(aNode, GEOMETRY_NODE_TEXT);
+}
+
+static nsIFrame*
+GetFirstNonAnonymousFrameForGeometryNode(const Optional<GeometryNode>& aNode,
+                                         nsINode* aDefaultNode)
+{
+  nsIFrame* f = GetFrameForGeometryNode(aNode, aDefaultNode);
+  if (f) {
+    f = nsLayoutUtils::GetFirstNonAnonymousFrame(f);
+  }
+  return f;
+}
+
+/**
+ * This can modify aFrame to point to a different frame. This is needed to
+ * handle SVG, where SVG elements can only compute a rect that's valid with
+ * respect to the "outer SVG" frame.
+ */
+static nsRect
+GetBoxRectForFrame(nsIFrame** aFrame, CSSBoxType aType)
+{
+  nsRect r;
+  nsIFrame* f = nsSVGUtils::GetOuterSVGFrameAndCoveredRegion(*aFrame, &r);
+  if (f) {
+    // For SVG, the BoxType is ignored.
+    *aFrame = f;
+    return r;
+  }
+
+  f = *aFrame;
+  switch (aType) {
+  case CSSBoxType::Content: r = f->GetContentRectRelativeToSelf(); break;
+  case CSSBoxType::Padding: r = f->GetPaddingRectRelativeToSelf(); break;
+  case CSSBoxType::Border: r = nsRect(nsPoint(0, 0), f->GetSize()); break;
+  case CSSBoxType::Margin: {
+    r = nsRect(nsPoint(0, 0), f->GetSize());
+    r.Inflate(f->GetUsedMargin());
+    break;
+  }
+  default: MOZ_ASSERT(false, "unknown box type"); return r;
+  }
+
+  return r;
+}
+
+class AccumulateQuadCallback : public nsLayoutUtils::BoxCallback {
+public:
+  AccumulateQuadCallback(nsISupports* aParentObject,
+                         nsTArray<nsRefPtr<DOMQuad> >& aResult,
+                         nsIFrame* aRelativeToFrame,
+                         const nsPoint& aRelativeToBoxTopLeft,
+                         CSSBoxType aBoxType)
+    : mParentObject(aParentObject)
+    , mResult(aResult)
+    , mRelativeToFrame(aRelativeToFrame)
+    , mRelativeToBoxTopLeft(aRelativeToBoxTopLeft)
+    , mBoxType(aBoxType)
+  {
+  }
+
+  virtual void AddBox(nsIFrame* aFrame) MOZ_OVERRIDE
+  {
+    nsIFrame* f = aFrame;
+    nsRect box = GetBoxRectForFrame(&f, mBoxType);
+    nsPoint appUnits[4] =
+      { box.TopLeft(), box.TopRight(), box.BottomRight(), box.BottomLeft() };
+    CSSPoint points[4];
+    for (uint32_t i = 0; i < 4; ++i) {
+      points[i] = CSSPoint(nsPresContext::AppUnitsToFloatCSSPixels(appUnits[i].x),
+                           nsPresContext::AppUnitsToFloatCSSPixels(appUnits[i].y));
+    }
+    nsLayoutUtils::TransformResult rv =
+      nsLayoutUtils::TransformPoints(f, mRelativeToFrame, 4, points);
+    if (rv == nsLayoutUtils::TRANSFORM_SUCCEEDED) {
+      CSSPoint delta(nsPresContext::AppUnitsToFloatCSSPixels(mRelativeToBoxTopLeft.x),
+                     nsPresContext::AppUnitsToFloatCSSPixels(mRelativeToBoxTopLeft.y));
+      for (uint32_t i = 0; i < 4; ++i) {
+        points[i] -= delta;
+      }
+    } else {
+      PodArrayZero(points);
+    }
+    mResult.AppendElement(new DOMQuad(mParentObject, points));
+  }
+
+  nsISupports* mParentObject;
+  nsTArray<nsRefPtr<DOMQuad> >& mResult;
+  nsIFrame* mRelativeToFrame;
+  nsPoint mRelativeToBoxTopLeft;
+  CSSBoxType mBoxType;
+};
+
+static nsPresContext*
+FindTopLevelPresContext(nsPresContext* aPC)
+{
+  bool isChrome = aPC->IsChrome();
+  nsPresContext* pc = aPC;
+  for (;;) {
+    nsPresContext* parent = pc->GetParentPresContext();
+    if (!parent || parent->IsChrome() != isChrome) {
+      return pc;
+    }
+    pc = parent;
+  }
+}
+
+static bool
+CheckFramesInSameTopLevelBrowsingContext(nsIFrame* aFrame1, nsIFrame* aFrame2)
+{
+  nsPresContext* pc1 = aFrame1->PresContext();
+  nsPresContext* pc2 = aFrame2->PresContext();
+  if (pc1 == pc2) {
+    return true;
+  }
+  if (nsContentUtils::IsCallerChrome()) {
+    return true;
+  }
+  if (FindTopLevelPresContext(pc1) == FindTopLevelPresContext(pc2)) {
+    return true;
+  }
+  return false;
+}
+
+void GetBoxQuads(nsINode* aNode,
+                 const dom::BoxQuadOptions& aOptions,
+                 nsTArray<nsRefPtr<DOMQuad> >& aResult,
+                 ErrorResult& aRv)
+{
+  nsIFrame* frame = GetFrameForNode(aNode);
+  if (!frame) {
+    // No boxes to return
+    return;
+  }
+  nsIDocument* ownerDoc = aNode->OwnerDoc();
+  nsIFrame* relativeToFrame =
+    GetFirstNonAnonymousFrameForGeometryNode(aOptions.mRelativeTo, ownerDoc);
+  if (!relativeToFrame) {
+    aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
+    return;
+  }
+  if (!CheckFramesInSameTopLevelBrowsingContext(frame, relativeToFrame)) {
+    aRv.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
+    return;
+  }
+  // GetBoxRectForFrame can modify relativeToFrame so call it first.
+  nsPoint relativeToTopLeft =
+      GetBoxRectForFrame(&relativeToFrame, CSSBoxType::Border).TopLeft();
+  AccumulateQuadCallback callback(ownerDoc, aResult, relativeToFrame,
+                                  relativeToTopLeft, aOptions.mBox);
+  nsLayoutUtils::GetAllInFlowBoxes(frame, &callback);
+}
+
+}
new file mode 100644
--- /dev/null
+++ b/layout/base/GeometryUtils.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_GEOMETRYUTILS_H_
+#define MOZILLA_GEOMETRYUTILS_H_
+
+#include "mozilla/ErrorResult.h"
+#include "nsTArray.h"
+#include "nsCOMPtr.h"
+
+/**
+ * This file defines utility functions for converting between layout
+ * coordinate systems.
+ */
+
+class nsINode;
+class nsIDocument;
+
+namespace mozilla {
+
+namespace dom {
+struct BoxQuadOptions;
+class DOMQuad;
+class Element;
+class Text;
+}
+
+/**
+ * Computes quads for aNode using aOptions, according to GeometryUtils.getBoxQuads.
+ * May set an error in aRv.
+ */
+void GetBoxQuads(nsINode* aNode,
+                 const dom::BoxQuadOptions& aOptions,
+                 nsTArray<nsRefPtr<dom::DOMQuad> >& aResult,
+                 ErrorResult& aRv);
+
+}
+
+#endif /* MOZILLA_GEOMETRYUTILS_H_ */
--- a/layout/base/moz.build
+++ b/layout/base/moz.build
@@ -55,25 +55,27 @@ EXPORTS += [
     'nsStyleChangeList.h',
     'ScrollbarStyles.h',
     'StackArena.h',
     'Units.h',
     'UnitTransforms.h',
 ]
 
 EXPORTS.mozilla += [
+    'GeometryUtils.h',
     'PaintTracker.h',
 ]
 
 UNIFIED_SOURCES += [
     'ActiveLayerTracker.cpp',
     'DisplayItemClip.cpp',
     'DisplayListClipState.cpp',
     'FrameLayerBuilder.cpp',
     'FramePropertyTable.cpp',
+    'GeometryUtils.cpp',
     'MaskLayerImageCache.cpp',
     'nsCaret.cpp',
     'nsCounterManager.cpp',
     'nsCSSColorUtils.cpp',
     'nsCSSFrameConstructor.cpp',
     'nsCSSRendering.cpp',
     'nsCSSRenderingBorders.cpp',
     'nsDisplayList.cpp',