mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
HTML - support for elements: <details> and <summary> (basic)
This commit is contained in:
@@ -13,7 +13,9 @@
|
||||
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/dom/HTMLDetailsElement.h"
|
||||
#include "mozilla/dom/HTMLSelectElement.h"
|
||||
#include "mozilla/dom/HTMLSummaryElement.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
@@ -87,6 +89,8 @@
|
||||
#include "nsSimplePageSequenceFrame.h"
|
||||
#include "nsTableOuterFrame.h"
|
||||
#include "nsIScrollableFrame.h"
|
||||
#include "DetailsFrame.h"
|
||||
#include "SummaryFrame.h"
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsIRootBox.h"
|
||||
@@ -938,7 +942,7 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShe
|
||||
mAdditionalStateBits(nsFrameState(0)),
|
||||
// If the fixed-pos containing block is equal to the abs-pos containing
|
||||
// block, use the abs-pos containing block's abs-pos list for fixed-pos
|
||||
// frames.
|
||||
// frames.
|
||||
mFixedPosIsAbsPos(aFixedContainingBlock == aAbsoluteContainingBlock),
|
||||
mHavePendingPopupgroup(false),
|
||||
mCreatingExtraFrames(false),
|
||||
@@ -972,7 +976,7 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell,
|
||||
mAdditionalStateBits(nsFrameState(0)),
|
||||
// If the fixed-pos containing block is equal to the abs-pos containing
|
||||
// block, use the abs-pos containing block's abs-pos list for fixed-pos
|
||||
// frames.
|
||||
// frames.
|
||||
mFixedPosIsAbsPos(aFixedContainingBlock == aAbsoluteContainingBlock),
|
||||
mHavePendingPopupgroup(false),
|
||||
mCreatingExtraFrames(false),
|
||||
@@ -3298,6 +3302,60 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsFrameConstructorState& aState,
|
||||
return fieldsetFrame;
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsCSSFrameConstructor::ConstructDetailsFrame(nsFrameConstructorState& aState,
|
||||
FrameConstructionItem& aItem,
|
||||
nsContainerFrame* aParentFrame,
|
||||
const nsStyleDisplay* aStyleDisplay,
|
||||
nsFrameItems& aFrameItems)
|
||||
{
|
||||
nsIContent* const content = aItem.mContent;
|
||||
nsStyleContext* const styleContext = aItem.mStyleContext;
|
||||
nsContainerFrame* geometricParent =
|
||||
aState.GetGeometricParent(aStyleDisplay, aParentFrame);
|
||||
|
||||
nsContainerFrame* detailsFrame = NS_NewDetailsFrame(mPresShell, styleContext);
|
||||
nsIFrame* frameToReturn = nullptr;
|
||||
|
||||
// Build a scroll frame to wrap details frame if necessary.
|
||||
if (aStyleDisplay->IsScrollableOverflow()) {
|
||||
nsContainerFrame* scrollFrame = nullptr;
|
||||
|
||||
nsRefPtr<nsStyleContext> detailsStyle =
|
||||
BeginBuildingScrollFrame(aState, content, styleContext, geometricParent ,
|
||||
nsCSSAnonBoxes::scrolledContent, false,
|
||||
scrollFrame);
|
||||
|
||||
aState.AddChild(scrollFrame, aFrameItems, content, styleContext,
|
||||
aParentFrame);
|
||||
|
||||
nsFrameItems scrollFrameItems;
|
||||
ConstructBlock(aState, aStyleDisplay, content,
|
||||
scrollFrame, scrollFrame,
|
||||
detailsStyle, &detailsFrame, scrollFrameItems,
|
||||
aStyleDisplay->IsPositioned(scrollFrame) ?
|
||||
scrollFrame : nullptr,
|
||||
aItem.mPendingBinding);
|
||||
|
||||
MOZ_ASSERT(scrollFrameItems.OnlyChild() == detailsFrame);
|
||||
|
||||
FinishBuildingScrollFrame(scrollFrame, detailsFrame);
|
||||
|
||||
frameToReturn = scrollFrame;
|
||||
} else {
|
||||
ConstructBlock(aState, aStyleDisplay, content, geometricParent,
|
||||
aParentFrame, styleContext,
|
||||
&detailsFrame, aFrameItems,
|
||||
aStyleDisplay->IsPositioned(detailsFrame) ?
|
||||
detailsFrame : nullptr,
|
||||
aItem.mPendingBinding);
|
||||
|
||||
frameToReturn = detailsFrame;
|
||||
}
|
||||
|
||||
return frameToReturn;
|
||||
}
|
||||
|
||||
static nsIFrame*
|
||||
FindAncestorWithGeneratedContentPseudo(nsIFrame* aFrame)
|
||||
{
|
||||
@@ -3489,6 +3547,19 @@ nsCSSFrameConstructor::FindHTMLData(Element* aElement,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aTag == nsGkAtoms::details || aTag == nsGkAtoms::summary) {
|
||||
if (!HTMLDetailsElement::IsDetailsEnabled()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (aTag == nsGkAtoms::summary &&
|
||||
(!aParentFrame || aParentFrame->GetType() != nsGkAtoms::detailsFrame)) {
|
||||
// <summary> is special only if it is a direct child of <details>. If it
|
||||
// isn't, construct it as a normal block frame instead of a summary frame.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const FrameConstructionDataByTag sHTMLData[] = {
|
||||
SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData),
|
||||
SIMPLE_TAG_CHAIN(mozgeneratedcontentimage,
|
||||
@@ -3518,7 +3589,11 @@ nsCSSFrameConstructor::FindHTMLData(Element* aElement,
|
||||
SIMPLE_TAG_CREATE(video, NS_NewHTMLVideoFrame),
|
||||
SIMPLE_TAG_CREATE(audio, NS_NewHTMLVideoFrame),
|
||||
SIMPLE_TAG_CREATE(progress, NS_NewProgressFrame),
|
||||
SIMPLE_TAG_CREATE(meter, NS_NewMeterFrame)
|
||||
SIMPLE_TAG_CREATE(meter, NS_NewMeterFrame),
|
||||
COMPLEX_TAG_CREATE(details, &nsCSSFrameConstructor::ConstructDetailsFrame),
|
||||
{ &nsGkAtoms::summary,
|
||||
FCDATA_DECL(FCDATA_ALLOW_BLOCK_STYLES | FCDATA_MAY_NEED_SCROLLFRAME,
|
||||
NS_NewSummaryFrame) }
|
||||
};
|
||||
|
||||
return FindDataByTag(aTag, aElement, aStyleContext, sHTMLData,
|
||||
@@ -5544,6 +5619,18 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
|
||||
}
|
||||
}
|
||||
|
||||
// When constructing a child of a non-open <details>, create only the frame
|
||||
// for the main <summary> element, and skip other elements.
|
||||
auto* details = HTMLDetailsElement::FromContentOrNull(parent);
|
||||
if (details && !details->Open()) {
|
||||
auto* summary = HTMLSummaryElement::FromContentOrNull(aContent);
|
||||
if (!summary || !summary->IsMainSummary()) {
|
||||
SetAsUndisplayedContent(aState, aItems, aContent, styleContext,
|
||||
isGeneratedContent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool isPopup = false;
|
||||
// Try to find frame construction data for this content
|
||||
const FrameConstructionData* data;
|
||||
@@ -6605,6 +6692,14 @@ nsCSSFrameConstructor::GetInsertionPrevSibling(InsertionPoint* aInsertion,
|
||||
// before the AdjustAppendParentForAfterContent call.
|
||||
aInsertion->mParentFrame =
|
||||
nsLayoutUtils::LastContinuationWithChild(aInsertion->mParentFrame);
|
||||
|
||||
// We should never get here with fieldsets or details, since they have
|
||||
// multiple insertion points.
|
||||
MOZ_ASSERT(aInsertion->mParentFrame->GetType()
|
||||
!= nsGkAtoms::fieldSetFrame &&
|
||||
aInsertion->mParentFrame->GetType() != nsGkAtoms::detailsFrame,
|
||||
"Parent frame should not be fieldset or details!");
|
||||
|
||||
// Deal with fieldsets
|
||||
aInsertion->mParentFrame =
|
||||
::GetAdjustedParentFrame(aInsertion->mParentFrame,
|
||||
@@ -7605,6 +7700,22 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
|
||||
return rv;
|
||||
}
|
||||
|
||||
// We should only get here with details when doing a single insertion because
|
||||
// we treat details frame as if it has multiple insertion points.
|
||||
MOZ_ASSERT(isSingleInsert || frameType != nsGkAtoms::detailsFrame);
|
||||
if (frameType == nsGkAtoms::detailsFrame) {
|
||||
// When inserting an element into <details>, just reframe the details frame
|
||||
// and let it figure out where the element should be laid out. It might seem
|
||||
// expensive to recreate the entire details frame, but it's the simplest way
|
||||
// to handle the insertion.
|
||||
LAYOUT_PHASE_TEMP_EXIT();
|
||||
nsresult rv =
|
||||
RecreateFramesForContent(insertion.mParentFrame->GetContent(), false,
|
||||
REMOVE_FOR_RECONSTRUCTION, nullptr);
|
||||
LAYOUT_PHASE_TEMP_REENTER();
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Don't construct kids of leaves
|
||||
if (insertion.mParentFrame->IsLeaf()) {
|
||||
// Clear lazy bits so we don't try to construct again.
|
||||
@@ -8760,6 +8871,12 @@ nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext,
|
||||
} else if (nsGkAtoms::rubyTextContainerFrame == frameType) {
|
||||
newFrame = NS_NewRubyTextContainerFrame(shell, styleContext);
|
||||
newFrame->Init(content, aParentFrame, aFrame);
|
||||
} else if (nsGkAtoms::detailsFrame == frameType) {
|
||||
newFrame = NS_NewDetailsFrame(shell, styleContext);
|
||||
newFrame->Init(content, aParentFrame, aFrame);
|
||||
} else if (nsGkAtoms::summaryFrame == frameType) {
|
||||
newFrame = NS_NewSummaryFrame(shell, styleContext);
|
||||
newFrame->Init(content, aParentFrame, aFrame);
|
||||
} else {
|
||||
NS_RUNTIMEABORT("unexpected frame type");
|
||||
}
|
||||
@@ -8928,6 +9045,13 @@ nsCSSFrameConstructor::GetInsertionPoint(nsIContent* aContainer,
|
||||
insertion.mMultiple = true;
|
||||
}
|
||||
|
||||
// A details frame moves the first summary frame to be its first child, so we
|
||||
// treat it as if it has multiple content insertion points.
|
||||
if (insertion.mParentFrame &&
|
||||
insertion.mParentFrame->GetType() == nsGkAtoms::detailsFrame) {
|
||||
insertion.mMultiple = true;
|
||||
}
|
||||
|
||||
return insertion;
|
||||
}
|
||||
|
||||
@@ -9079,6 +9203,17 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (insertionFrame && insertionFrame->GetType() == nsGkAtoms::summaryFrame &&
|
||||
aFrame->GetParent()->GetType() == nsGkAtoms::detailsFrame) {
|
||||
// When removing a summary frame, we should reframe the parent details frame
|
||||
// to ensure that another summary is used or the default summary is
|
||||
// generated.
|
||||
*aResult = RecreateFramesForContent(aFrame->GetParent()->GetContent(),
|
||||
false, REMOVE_FOR_RECONSTRUCTION,
|
||||
aDestroyedFramesFor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now check for possibly needing to reconstruct due to a pseudo parent
|
||||
nsIFrame* inFlowFrame =
|
||||
(aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) ?
|
||||
@@ -11399,7 +11534,9 @@ nsCSSFrameConstructor::ConstructBlock(nsFrameConstructorState& aState,
|
||||
{
|
||||
// Create column wrapper if necessary
|
||||
nsContainerFrame* blockFrame = *aNewFrame;
|
||||
NS_ASSERTION(blockFrame->GetType() == nsGkAtoms::blockFrame, "not a block frame?");
|
||||
NS_ASSERTION((blockFrame->GetType() == nsGkAtoms::blockFrame ||
|
||||
blockFrame->GetType() == nsGkAtoms::detailsFrame),
|
||||
"not a block frame nor a details frame?");
|
||||
nsContainerFrame* parent = aParentFrame;
|
||||
nsRefPtr<nsStyleContext> blockStyle = aStyleContext;
|
||||
const nsStyleColumn* columns = aStyleContext->StyleColumn();
|
||||
|
||||
Reference in New Issue
Block a user