зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1102175 Part 1 - Propagate used writing-mode from body element to its ancestors. r=jfkthame
Differential Revision: https://phabricator.services.mozilla.com/D45481 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
a5bb9b3228
Коммит
1ce98223f5
|
@ -2314,6 +2314,33 @@ nsIFrame* nsCSSFrameConstructor::ConstructDocElementFrame(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (aDocElement->IsHTMLElement() &&
|
||||
mDocElementContainingBlock->IsCanvasFrame()) {
|
||||
// This implements "The Principal Writing Mode".
|
||||
// https://drafts.csswg.org/css-writing-modes-3/#principal-flow
|
||||
//
|
||||
// If there's a <body> element, its writing-mode, direction, and
|
||||
// text-orientation override the root element's used value.
|
||||
//
|
||||
// We need to copy <body>'s WritingMode to mDocElementContainingBlock before
|
||||
// construct mRootElementFrame so that anonymous internal frames such as
|
||||
// <html> with table style can copy their parent frame's mWritingMode in
|
||||
// nsFrame::Init().
|
||||
MOZ_ASSERT(!mRootElementFrame,
|
||||
"We need to copy <body>'s principal writing-mode before "
|
||||
"constructing mRootElementFrame.");
|
||||
|
||||
Element* body = mDocument->GetBodyElement();
|
||||
if (body) {
|
||||
RefPtr<ComputedStyle> bodyStyle = ResolveComputedStyle(body);
|
||||
mDocElementContainingBlock->PropagateWritingModeToSelfAndAncestors(
|
||||
WritingMode(bodyStyle));
|
||||
} else {
|
||||
mDocElementContainingBlock->PropagateWritingModeToSelfAndAncestors(
|
||||
mDocElementContainingBlock->GetWritingMode());
|
||||
}
|
||||
}
|
||||
|
||||
nsFrameConstructorSaveState docElementContainingBlockAbsoluteSaveState;
|
||||
if (mHasRootAbsPosContainingBlock) {
|
||||
// Push the absolute containing block now so we can absolutely position
|
||||
|
@ -6813,7 +6840,7 @@ void nsCSSFrameConstructor::ContentAppended(nsIContent* aFirstNewContent,
|
|||
}
|
||||
|
||||
LAYOUT_PHASE_TEMP_EXIT();
|
||||
if (WipeInsertionParent(parentFrame)) {
|
||||
if (WipeInsertionParent(parentFrame, aFirstNewContent, nullptr)) {
|
||||
LAYOUT_PHASE_TEMP_REENTER();
|
||||
return;
|
||||
}
|
||||
|
@ -7214,7 +7241,7 @@ void nsCSSFrameConstructor::ContentRangeInserted(
|
|||
}
|
||||
|
||||
LAYOUT_PHASE_TEMP_EXIT();
|
||||
if (WipeInsertionParent(insertion.mParentFrame)) {
|
||||
if (WipeInsertionParent(insertion.mParentFrame, aStartChild, aEndChild)) {
|
||||
LAYOUT_PHASE_TEMP_REENTER();
|
||||
return;
|
||||
}
|
||||
|
@ -8414,6 +8441,17 @@ bool nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
|
|||
"placeholder for primary frame has previous continuations?");
|
||||
nsIFrame* parent = inFlowFrame->GetParent();
|
||||
|
||||
if (aFrame->GetContent() == mDocument->GetBodyElement()) {
|
||||
// If the frame of the canonical body element is removed (either because of
|
||||
// removing of the element, or removing for frame construction like
|
||||
// writing-mode changed), we need to reframe the root element so that the
|
||||
// root element's frames has the correct writing-mode propagated from body
|
||||
// element. (See nsCSSFrameConstructor::ConstructDocElementFrame.)
|
||||
TRACE("Root");
|
||||
RecreateFramesForContent(mDocument->GetRootElement(), InsertionKind::Async);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (inFlowFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
|
||||
nsIFrame* grandparent = parent->GetParent();
|
||||
MOZ_ASSERT(grandparent);
|
||||
|
@ -11344,13 +11382,34 @@ static bool IsSafeToAppendToIBSplitInline(nsIFrame* aParentFrame,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool nsCSSFrameConstructor::WipeInsertionParent(nsContainerFrame* aFrame) {
|
||||
bool nsCSSFrameConstructor::WipeInsertionParent(nsContainerFrame* aFrame,
|
||||
nsIContent* aStartChild,
|
||||
nsIContent* aEndChild) {
|
||||
#define TRACE(reason) \
|
||||
PROFILER_TRACING("Layout", "WipeInsertionParent: " reason, LAYOUT, \
|
||||
TRACING_EVENT)
|
||||
|
||||
MOZ_ASSERT(aStartChild, "Must always pass aStartChild!");
|
||||
|
||||
const LayoutFrameType frameType = aFrame->Type();
|
||||
|
||||
if (aFrame->GetContent() == mDocument->GetRootElement()) {
|
||||
// If we insert a content that becomes the canonical body element, we need
|
||||
// to reframe the root element so that the root element's frames has the
|
||||
// correct writing-mode propagated from body element. (See
|
||||
// nsCSSFrameConstructor::ConstructDocElementFrame.)
|
||||
nsIContent* bodyElement = mDocument->GetBodyElement();
|
||||
for (nsIContent* child = aStartChild; child != aEndChild;
|
||||
child = child->GetNextSibling()) {
|
||||
if (child == bodyElement) {
|
||||
TRACE("Root");
|
||||
RecreateFramesForContent(mDocument->GetRootElement(),
|
||||
InsertionKind::Async);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(emilio): This looks terribly inefficient if you insert elements deep
|
||||
// in a MathML subtree.
|
||||
if (aFrame->IsFrameOfType(nsIFrame::eMathML)) {
|
||||
|
|
|
@ -1906,14 +1906,19 @@ class nsCSSFrameConstructor final : public nsFrameManager {
|
|||
// rebuild the entire subtree when we insert or append new content under
|
||||
// aFrame.
|
||||
//
|
||||
// [aStartChild, aEndChild) is the range of the children to be inserted.
|
||||
// aStartChild must be non-null; aEndChild may be null to indicate that we are
|
||||
// appending the range includes all kids after aStartChild.
|
||||
//
|
||||
// This is similar to WipeContainingBlock(), but is called before constructing
|
||||
// any frame construction items. Any container frames which need reframing
|
||||
// regardless of the content inserted or appended can add a check in this
|
||||
// method.
|
||||
// any frame construction items. Any container frames which need reframing by
|
||||
// checking only the content inserted or appended, not the style of the
|
||||
// content, can add a check in this method.
|
||||
//
|
||||
// @return true if we reconstructed the insertion parent frame; false
|
||||
// otherwise
|
||||
bool WipeInsertionParent(nsContainerFrame* aFrame);
|
||||
bool WipeInsertionParent(nsContainerFrame* aFrame, nsIContent* aStartChild,
|
||||
nsIContent* aEndChild);
|
||||
|
||||
// Determine whether we need to wipe out what we just did and start over
|
||||
// because we're doing something like adding block kids to an inline frame
|
||||
|
|
|
@ -247,7 +247,6 @@ void nsCanvasFrame::SetInitialChildList(ChildListID aListID,
|
|||
aChildList.OnlyChild(),
|
||||
"Primary child list can have at most one frame in it");
|
||||
nsContainerFrame::SetInitialChildList(aListID, aChildList);
|
||||
MaybePropagateRootElementWritingMode();
|
||||
}
|
||||
|
||||
void nsCanvasFrame::AppendFrames(ChildListID aListID, nsFrameList& aFrameList) {
|
||||
|
@ -264,7 +263,6 @@ void nsCanvasFrame::AppendFrames(ChildListID aListID, nsFrameList& aFrameList) {
|
|||
nsFrame::VerifyDirtyBitSet(aFrameList);
|
||||
#endif
|
||||
nsContainerFrame::AppendFrames(aListID, aFrameList);
|
||||
MaybePropagateRootElementWritingMode();
|
||||
}
|
||||
|
||||
void nsCanvasFrame::InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
|
||||
|
@ -274,7 +272,6 @@ void nsCanvasFrame::InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
|
|||
// as appending
|
||||
MOZ_ASSERT(!aPrevFrame, "unexpected previous sibling frame");
|
||||
AppendFrames(aListID, aFrameList);
|
||||
MaybePropagateRootElementWritingMode();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -832,15 +829,6 @@ nsresult nsCanvasFrame::GetContentForEvent(WidgetEvent* aEvent,
|
|||
return rv;
|
||||
}
|
||||
|
||||
void nsCanvasFrame::MaybePropagateRootElementWritingMode() {
|
||||
nsIFrame* child = PrincipalChildList().FirstChild();
|
||||
if (child && child->GetContent() &&
|
||||
child->GetContent() == PresContext()->Document()->GetRootElement()) {
|
||||
nsIFrame* childPrimary = child->GetContent()->GetPrimaryFrame();
|
||||
PropagateRootElementWritingMode(childPrimary->GetWritingMode());
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
nsresult nsCanvasFrame::GetFrameName(nsAString& aResult) const {
|
||||
return MakeFrameName(NS_LITERAL_STRING("Canvas"), aResult);
|
||||
|
|
|
@ -118,10 +118,6 @@ class nsCanvasFrame final : public nsContainerFrame,
|
|||
nsRect CanvasArea() const;
|
||||
|
||||
protected:
|
||||
// Utility function to propagate the WritingMode from our first child to
|
||||
// 'this' and all its ancestors.
|
||||
void MaybePropagateRootElementWritingMode();
|
||||
|
||||
// Data members
|
||||
bool mDoPaintFocus;
|
||||
bool mAddedScrollPositionListener;
|
||||
|
|
|
@ -638,6 +638,15 @@ void nsFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
|
|||
PresContext()->ConstructedFrame();
|
||||
}
|
||||
if (GetParent()) {
|
||||
if (MOZ_UNLIKELY(mContent == PresContext()->Document()->GetRootElement() &&
|
||||
mContent == GetParent()->GetContent())) {
|
||||
// Our content is the root element and we have the same content as our
|
||||
// parent. That is, we are the internal anonymous frame of the root
|
||||
// element. Copy the used mWritingMode from our parent because
|
||||
// mDocElementContainingBlock gets its mWritingMode from <body>.
|
||||
mWritingMode = GetParent()->GetWritingMode();
|
||||
}
|
||||
|
||||
// Copy some state bits from our parent (the bits that should apply
|
||||
// recursively throughout a subtree). The bits are sorted according to their
|
||||
// order in nsFrameStateBits.h.
|
||||
|
|
|
@ -894,8 +894,12 @@ class nsIFrame : public nsQueryFrame {
|
|||
* It's usually the 'writing-mode' computed value, but there are exceptions:
|
||||
* * inner table frames copy the value from the table frame
|
||||
* (@see nsTableRowGroupFrame::Init, nsTableRowFrame::Init etc)
|
||||
* * the root element frame propagates its value to its ancestors
|
||||
* (@see nsCanvasFrame::MaybePropagateRootElementWritingMode)
|
||||
* * the root element frame propagates its value to its ancestors.
|
||||
* The value may obtain from the principal <body> element.
|
||||
* (@see nsCSSFrameConstructor::ConstructDocElementFrame)
|
||||
* * the internal anonymous frames of the root element copy their value
|
||||
* from the parent.
|
||||
* (@see nsFrame::Init)
|
||||
* * a scrolled frame propagates its value to its ancestor scroll frame
|
||||
* (@see nsHTMLScrollFrame::ReloadChildFrames)
|
||||
*/
|
||||
|
@ -4255,6 +4259,11 @@ class nsIFrame : public nsQueryFrame {
|
|||
mozilla::gfx::CompositorHitTestInfo GetCompositorHitTestInfo(
|
||||
nsDisplayListBuilder* aBuilder);
|
||||
|
||||
/**
|
||||
* Copies aWM to mWritingMode on 'this' and all its ancestors.
|
||||
*/
|
||||
inline void PropagateWritingModeToSelfAndAncestors(mozilla::WritingMode aWM);
|
||||
|
||||
protected:
|
||||
static void DestroyAnonymousContent(nsPresContext* aPresContext,
|
||||
already_AddRefed<nsIContent>&& aContent);
|
||||
|
@ -4309,11 +4318,6 @@ class nsIFrame : public nsQueryFrame {
|
|||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Copies aRootElemWM to mWritingMode on 'this' and all its ancestors.
|
||||
*/
|
||||
inline void PropagateRootElementWritingMode(mozilla::WritingMode aRootElemWM);
|
||||
|
||||
void MarkInReflow() {
|
||||
#ifdef DEBUG_dbaron_off
|
||||
// bug 81268
|
||||
|
|
|
@ -144,11 +144,11 @@ nscoord nsIFrame::BaselineBOffset(mozilla::WritingMode aWM,
|
|||
return SynthesizeBaselineBOffsetFromBorderBox(aWM, aBaselineGroup);
|
||||
}
|
||||
|
||||
void nsIFrame::PropagateRootElementWritingMode(
|
||||
mozilla::WritingMode aRootElemWM) {
|
||||
void nsIFrame::PropagateWritingModeToSelfAndAncestors(
|
||||
mozilla::WritingMode aWM) {
|
||||
MOZ_ASSERT(IsCanvasFrame());
|
||||
for (auto f = this; f; f = f->GetParent()) {
|
||||
f->mWritingMode = aRootElemWM;
|
||||
f->mWritingMode = aWM;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче