/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */
/** * 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 = SVGUtils::GetOuterSVGFrameAndCoveredRegion(*aFrame, &r); if (f && f != *aFrame) { // For non-outer SVG frames, 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 = f->GetMarginRectRelativeToSelf(); break; default:
MOZ_ASSERT(false, "unknown box type"); return r;
}
return r;
}
class MOZ_STACK_CLASS AccumulateQuadCallback final
: public nsLayoutUtils::BoxCallback { public:
AccumulateQuadCallback(Document* aParentObject,
nsTArray<RefPtr<DOMQuad>>& aResult,
nsIFrame* aRelativeToFrame, const nsPoint& aRelativeToBoxTopLeft, const BoxQuadOptions& aOptions)
: mParentObject(ToSupports(aParentObject)),
mResult(aResult),
mRelativeToFrame(aRelativeToFrame),
mRelativeToBoxTopLeft(aRelativeToBoxTopLeft),
mOptions(aOptions) { if (mOptions.mBox == CSSBoxType::Margin) { // Don't include the caption margin when computing margins for a // table
mIncludeCaptionBoxForTable = false;
}
}
void AddBox(nsIFrame* aFrame) override {
nsIFrame* f = aFrame; if (mOptions.mBox == CSSBoxType::Margin && f->IsTableFrame()) { // Margin boxes for table frames should be taken from the table wrapper // frame, since that has the margin.
f = f->GetParent();
} const nsRect box = GetBoxRectForFrame(&f, mOptions.mBox);
CSSPoint points[4] = {CSSPoint::FromAppUnits(box.TopLeft()),
CSSPoint::FromAppUnits(box.TopRight()),
CSSPoint::FromAppUnits(box.BottomRight()),
CSSPoint::FromAppUnits(box.BottomLeft())}; constauto delta = [&]() -> Maybe<CSSPoint> { if (mOptions.mIgnoreTransforms) { return Some(CSSPoint::FromAppUnits(f->GetOffsetTo(mRelativeToFrame) -
mRelativeToBoxTopLeft));
}
nsLayoutUtils::TransformResult rv = nsLayoutUtils::TransformPoints(
RelativeTo{f}, RelativeTo{mRelativeToFrame}, 4, points); if (rv != nsLayoutUtils::TRANSFORM_SUCCEEDED) { return Nothing();
} return Some(CSSPoint::FromAppUnits(-mRelativeToBoxTopLeft));
}(); if (delta) { for (auto& point : points) {
point += *delta;
}
} else {
PodArrayZero(points);
}
mResult.AppendElement(new DOMQuad(mParentObject, points));
}
void GetBoxQuads(nsINode* aNode, const dom::BoxQuadOptions& aOptions,
nsTArray<RefPtr<DOMQuad>>& aResult, CallerType aCallerType,
ErrorResult& aRv) {
nsIFrame* frame = GetFrameForNode(aNode, aOptions); if (!frame) { // No boxes to return return;
}
AutoWeakFrame weakFrame(frame);
Document* ownerDoc = aNode->OwnerDoc();
nsIFrame* relativeToFrame = GetFirstNonAnonymousFrameForGeometryNode(
aOptions.mRelativeTo, ownerDoc, aOptions); // The first frame might be destroyed now if the above call lead to an // EnsureFrameForTextNode call. We need to get the first frame again // when that happens and re-check it. if (!weakFrame.IsAlive()) {
frame = GetFrameForNode(aNode, aOptions); if (!frame) { // No boxes to return return;
}
} if (!relativeToFrame) { // XXXbz There's no spec for this. return aRv.ThrowNotFoundError("No box to get quads relative to");
} if (!CheckFramesInSameTopLevelBrowsingContext(frame, relativeToFrame,
aCallerType)) {
aRv.ThrowNotFoundError( "Can't get quads relative to a box in a different toplevel browsing " "context"); return;
} // GetBoxRectForFrame can modify relativeToFrame so call it first.
nsPoint relativeToTopLeft =
GetBoxRectForFrame(&relativeToFrame, CSSBoxType::Border).TopLeft();
AccumulateQuadCallback callback(ownerDoc, aResult, relativeToFrame,
relativeToTopLeft, aOptions);
// Bug 1624653: Refactor this to get boxes in layer pixels, which we will // then convert into CSS units.
nsLayoutUtils::GetAllInFlowBoxes(frame, &callback);
}
void GetBoxQuadsFromWindowOrigin(nsINode* aNode, const dom::BoxQuadOptions& aOptions,
nsTArray<RefPtr<DOMQuad>>& aResult,
ErrorResult& aRv) { // We want the quads relative to the window. To do this, we ignore the // provided aOptions.mRelativeTo and instead use the document node of // the top-most in-process document. Later, we'll check if there is a // browserChild associated with that document, and if so, transform the // calculated quads with the browserChild's to-parent matrix, which // will get us to top-level coordinates. if (aOptions.mRelativeTo.WasPassed()) { return aRv.ThrowNotSupportedError( "Can't request quads in window origin space relative to another " "node.");
}
// We're going to call GetBoxQuads with our parameters, but we supply // a new BoxQuadOptions object that uses the top in-process document // as the relativeTo target.
BoxQuadOptions bqo(aOptions);
// Bug 1624653: Refactor this to get boxes in layer pixels, which we can // transform directly with the GetChildToParentConversionMatrix below, // and convert to CSS units as a final step.
GetBoxQuads(aNode, bqo, aResult, CallerType::System, aRv); if (aRv.Failed()) { return;
}
// Now we have aResult filled with DOMQuads with values relative to the // top in-process document. See if topInProcessDoc is associated with a // BrowserChild, and if it is, get its transformation matrix and use that // to transform the DOMQuads in place to make them relative to the window // origin.
nsIDocShell* docShell = topInProcessDoc->GetDocShell(); if (!docShell) { return aRv.ThrowInvalidStateError( "Returning untranslated quads because top in process document has " "no docshell.");
}
BrowserChild* browserChild = BrowserChild::GetFrom(docShell); if (!browserChild) { return;
}
// For each DOMQuad in aResult, change the css units into layer pixels, // then transform them by matrix, then change them back into css units // and overwrite the original points.
LayoutDeviceToCSSScale ld2cScale((float)appUnitsPerDevPixel /
(float)AppUnitsPerCSSPixel());
CSSToLayoutDeviceScale c2ldScale = ld2cScale.Inverse();
for (auto& quad : aResult) { for (uint32_t i = 0; i < 4; i++) {
DOMPoint* p = quad->Point(i);
CSSPoint cp(p->X(), p->Y());
staticvoid TransformPoints(nsINode* aTo, const GeometryNode& aFrom,
uint32_t aPointCount, CSSPoint* aPoints, const ConvertCoordinateOptions& aOptions,
CallerType aCallerType, ErrorResult& aRv) {
nsIFrame* fromFrame =
GetFirstNonAnonymousFrameForGeometryNode(aFrom, aOptions);
AutoWeakFrame weakFrame(fromFrame);
nsIFrame* toFrame = GetFirstNonAnonymousFrameForNode(aTo, aOptions); // The first frame might be destroyed now if the above call lead to an // EnsureFrameForTextNode call. We need to get the first frame again // when that happens. if (fromFrame && !weakFrame.IsAlive()) {
fromFrame = GetFirstNonAnonymousFrameForGeometryNode(aFrom, aOptions);
} if (!fromFrame || !toFrame) {
aRv.ThrowNotFoundError( "Can't transform coordinates between nonexistent boxes"); return;
} if (!CheckFramesInSameTopLevelBrowsingContext(fromFrame, toFrame,
aCallerType)) {
aRv.ThrowNotFoundError( "Can't transform coordinates between boxes in different toplevel " "browsing contexts"); return;
}
nsPoint fromOffset =
GetBoxRectForFrame(&fromFrame, aOptions.mFromBox).TopLeft();
nsPoint toOffset = GetBoxRectForFrame(&toFrame, aOptions.mToBox).TopLeft();
CSSPoint fromOffsetGfx(nsPresContext::AppUnitsToFloatCSSPixels(fromOffset.x),
nsPresContext::AppUnitsToFloatCSSPixels(fromOffset.y)); for (uint32_t i = 0; i < aPointCount; ++i) {
aPoints[i] += fromOffsetGfx;
}
nsLayoutUtils::TransformResult rv = nsLayoutUtils::TransformPoints(
RelativeTo{fromFrame}, RelativeTo{toFrame}, aPointCount, aPoints); if (rv == nsLayoutUtils::TRANSFORM_SUCCEEDED) {
CSSPoint toOffsetGfx(nsPresContext::AppUnitsToFloatCSSPixels(toOffset.x),
nsPresContext::AppUnitsToFloatCSSPixels(toOffset.y)); for (uint32_t i = 0; i < aPointCount; ++i) {
aPoints[i] -= toOffsetGfx;
}
} else {
PodZero(aPoints, aPointCount);
}
}
already_AddRefed<DOMQuad> ConvertQuadFromNode(
nsINode* aTo, dom::DOMQuad& aQuad, const GeometryNode& aFrom, const dom::ConvertCoordinateOptions& aOptions, CallerType aCallerType,
ErrorResult& aRv) {
CSSPoint points[4]; for (uint32_t i = 0; i < 4; ++i) {
DOMPoint* p = aQuad.Point(i); if (p->W() != 1.0 || p->Z() != 0.0) {
aRv.ThrowInvalidStateError("Point is not 2d"); return nullptr;
}
points[i] = CSSPoint(p->X(), p->Y());
}
TransformPoints(aTo, aFrom, 4, points, aOptions, aCallerType, aRv); if (aRv.Failed()) { return nullptr;
} return MakeAndAddRef<DOMQuad>(aTo->GetParentObject().mObject, points);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.