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:
Ting-Yu Lin 2019-10-09 22:11:02 +00:00
Родитель a5bb9b3228
Коммит 1ce98223f5
7 изменённых файлов: 94 добавлений и 33 удалений

Просмотреть файл

@ -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;
}
}