Bug 473390 part 7. Switch HTML frame construction over to the new setup. r+sr=roc

This commit is contained in:
Boris Zbarsky 2009-01-19 13:31:32 -05:00
Родитель 225d63e68a
Коммит c5143ee137
2 изменённых файлов: 462 добавлений и 479 удалений

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

@ -1149,8 +1149,7 @@ public:
// Function to return the proper geometric parent for a frame with display
// struct given by aStyleDisplay and parent's frame given by
// aContentParentFrame. If the frame is not allowed to be positioned, pass
// false for aCanBePositioned.
// aContentParentFrame.
nsIFrame* GetGeometricParent(const nsStyleDisplay* aStyleDisplay,
nsIFrame* aContentParentFrame);
@ -2183,99 +2182,6 @@ nsCSSFrameConstructor::CreateGeneratedContentFrame(nsFrameConstructorState& aSta
aState.mAdditionalStateBits = savedStateBits;
}
nsresult
nsCSSFrameConstructor::CreateInputFrame(nsFrameConstructorState& aState,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsIAtom* aTag,
nsStyleContext* aStyleContext,
nsIFrame** aFrame,
const nsStyleDisplay* aStyleDisplay,
PRBool& aFrameHasBeenInitialized,
PRBool& aAddedToFrameList,
nsFrameItems& aFrameItems,
PRBool aHasPseudoParent)
{
// Make sure to keep IsSpecialContent in synch with this code
// Note: do not do anything in this method that assumes pseudo-frames have
// been processed. If you feel the urge to do something like that, fix
// callers accordingly.
nsCOMPtr<nsIFormControl> control = do_QueryInterface(aContent);
if (!control) {
NS_ERROR("input doesn't implement nsIFormControl?");
return NS_OK;
}
switch (control->GetType()) {
case NS_FORM_INPUT_SUBMIT:
case NS_FORM_INPUT_RESET:
case NS_FORM_INPUT_BUTTON:
{
nsresult rv = ConstructButtonFrame(aState, aContent, aParentFrame,
aTag, aStyleContext, aFrame,
aStyleDisplay, aFrameItems,
aHasPseudoParent);
aAddedToFrameList = PR_TRUE;
aFrameHasBeenInitialized = PR_TRUE;
return rv;
}
case NS_FORM_INPUT_CHECKBOX:
*aFrame = NS_NewGfxCheckboxControlFrame(mPresShell, aStyleContext);
return *aFrame ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
case NS_FORM_INPUT_RADIO:
*aFrame = NS_NewGfxRadioControlFrame(mPresShell, aStyleContext);
return *aFrame ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
case NS_FORM_INPUT_FILE:
{
*aFrame = NS_NewFileControlFrame(mPresShell, aStyleContext);
return *aFrame ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
case NS_FORM_INPUT_HIDDEN:
return NS_OK; // this does not create a frame so it needs special handling
// in IsSpecialContent
case NS_FORM_INPUT_IMAGE:
return CreateHTMLImageFrame(aContent, aStyleContext,
NS_NewImageControlFrame, aFrame);
case NS_FORM_INPUT_TEXT:
case NS_FORM_INPUT_PASSWORD:
{
*aFrame = NS_NewTextControlFrame(mPresShell, aStyleContext);
return NS_UNLIKELY(!*aFrame) ? NS_ERROR_OUT_OF_MEMORY : NS_OK;
}
default:
NS_ASSERTION(0, "Unknown input type!");
return NS_ERROR_INVALID_ARG;
}
}
nsresult
nsCSSFrameConstructor::CreateHTMLImageFrame(nsIContent* aContent,
nsStyleContext* aStyleContext,
ImageFrameCreatorFunc aFunc,
nsIFrame** aFrame)
{
*aFrame = nsnull;
// Make sure to keep IsSpecialContent in synch with this code
if (nsImageFrame::ShouldCreateImageFrameFor(aContent, aStyleContext)) {
*aFrame = (*aFunc)(mPresShell, aStyleContext);
if (NS_UNLIKELY(!*aFrame))
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
static PRBool
TextIsOnlyWhitespace(nsIContent* aContent)
{
@ -3192,66 +3098,18 @@ nsCSSFrameConstructor::GetParentFrame(PRInt32 aNameSpaceID,
return rv;
}
static PRBool
IsSpecialContent(nsIContent* aContent,
nsIAtom* aTag,
PRInt32 aNameSpaceID,
nsStyleContext* aStyleContext)
/* static */
PRBool
nsCSSFrameConstructor::IsSpecialContent(nsIContent* aContent,
nsIAtom* aTag,
PRInt32 aNameSpaceID,
nsStyleContext* aStyleContext)
{
// Gross hack. Return true if this is a content node that we'd create a
// frame for based on something other than display -- in other words if this
// is a node that could never have a nsTableCellFrame, for example.
if (aContent->IsNodeOfType(nsINode::eHTML) ||
aNameSpaceID == kNameSpaceID_XHTML) {
// XXXbz this is duplicating some logic from ConstructHTMLFrame....
// Would be nice to avoid that. :(
if (aTag == nsGkAtoms::input) {
nsCOMPtr<nsIFormControl> control = do_QueryInterface(aContent);
if (control) {
PRInt32 type = control->GetType();
if (NS_FORM_INPUT_HIDDEN == type) {
return PR_FALSE; // input hidden does not create a special frame
}
else if (NS_FORM_INPUT_IMAGE == type) {
return nsImageFrame::ShouldCreateImageFrameFor(aContent, aStyleContext);
}
}
return PR_TRUE;
}
if (aTag == nsGkAtoms::img ||
aTag == nsGkAtoms::mozgeneratedcontentimage) {
return nsImageFrame::ShouldCreateImageFrameFor(aContent, aStyleContext);
}
if (aTag == nsGkAtoms::object ||
aTag == nsGkAtoms::applet ||
aTag == nsGkAtoms::embed) {
return !(aContent->IntrinsicState() &
(NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_USERDISABLED |
NS_EVENT_STATE_SUPPRESSED));
}
return
aTag == nsGkAtoms::br ||
aTag == nsGkAtoms::wbr ||
aTag == nsGkAtoms::textarea ||
aTag == nsGkAtoms::select ||
aTag == nsGkAtoms::fieldset ||
aTag == nsGkAtoms::legend ||
aTag == nsGkAtoms::frameset ||
aTag == nsGkAtoms::iframe ||
aTag == nsGkAtoms::spacer ||
aTag == nsGkAtoms::button ||
aTag == nsGkAtoms::isindex ||
aTag == nsGkAtoms::canvas ||
#if defined(MOZ_MEDIA)
aTag == nsGkAtoms::video ||
aTag == nsGkAtoms::audio ||
#endif
PR_FALSE;
if (FindHTMLData(aContent, aTag, aNameSpaceID, aStyleContext)) {
return PR_TRUE;
}
@ -3936,15 +3794,6 @@ NeedFrameFor(nsIFrame* aParentFrame,
|| aParentFrame->IsGeneratedContentFrame();
}
const nsStyleDisplay*
nsCSSFrameConstructor::GetDisplay(nsIFrame* aFrame)
{
if (nsnull == aFrame) {
return nsnull;
}
return aFrame->GetStyleContext()->GetStyleDisplay();
}
/***********************************************
* END TABLE SECTION
***********************************************/
@ -4642,15 +4491,10 @@ nsCSSFrameConstructor::ConstructButtonFrame(nsFrameConstructorState& aState,
nsIFrame* aParentFrame,
nsIAtom* aTag,
nsStyleContext* aStyleContext,
nsIFrame** aNewFrame,
const nsStyleDisplay* aStyleDisplay,
nsFrameItems& aFrameItems,
PRBool aHasPseudoParent)
nsIFrame** aNewFrame)
{
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems);
}
*aNewFrame = nsnull;
nsIFrame* buttonFrame = nsnull;
@ -4766,10 +4610,9 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState,
nsIFrame* aParentFrame,
nsIAtom* aTag,
nsStyleContext* aStyleContext,
nsIFrame*& aNewFrame,
const nsStyleDisplay* aStyleDisplay,
PRBool& aFrameHasBeenInitialized,
nsFrameItems& aFrameItems)
nsFrameItems& aFrameItems,
nsIFrame** aNewFrame)
{
nsresult rv = NS_OK;
const PRInt32 kNoSizeSpecified = -1;
@ -4867,8 +4710,7 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState,
comboboxFrame->SetInitialChildList(nsGkAtoms::selectPopupList,
popupItems.childList);
aNewFrame = comboboxFrame;
aFrameHasBeenInitialized = PR_TRUE;
*aNewFrame = comboboxFrame;
aState.mFrameState = historyState;
if (aState.mFrameState && aState.mFrameManager) {
// Restore frame state for the entire subtree of |comboboxFrame|.
@ -4896,9 +4738,7 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState,
InitializeSelectFrame(aState, listFrame, scrolledFrame, aContent,
aParentFrame, aStyleContext, PR_FALSE, aFrameItems);
aNewFrame = listFrame;
aFrameHasBeenInitialized = PR_TRUE;
*aNewFrame = listFrame;
}
}
return rv;
@ -4995,10 +4835,9 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsFrameConstructorState& aState,
nsIFrame* aParentFrame,
nsIAtom* aTag,
nsStyleContext* aStyleContext,
nsIFrame*& aNewFrame,
nsFrameItems& aFrameItems,
const nsStyleDisplay* aStyleDisplay,
PRBool& aFrameHasBeenInitialized)
nsFrameItems& aFrameItems,
nsIFrame** aNewFrame)
{
nsIFrame* newFrame = NS_NewFieldSetFrame(mPresShell, aStyleContext);
if (NS_UNLIKELY(!newFrame)) {
@ -5077,10 +4916,7 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsFrameConstructorState& aState,
newFrame->SetInitialChildList(nsnull, legendFrame ? legendFrame : blockFrame);
// our new frame returned is the top frame which is the list frame.
aNewFrame = newFrame;
// yes we have already initialized our frame
aFrameHasBeenInitialized = PR_TRUE;
*aNewFrame = newFrame;
return NS_OK;
}
@ -5168,259 +5004,281 @@ nsCSSFrameConstructor::ConstructTextFrame(nsFrameConstructorState& aState,
return rv;
}
nsresult
nsCSSFrameConstructor::ConstructHTMLFrame(nsFrameConstructorState& aState,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsIAtom* aTag,
PRInt32 aNameSpaceID,
nsStyleContext* aStyleContext,
nsFrameItems& aFrameItems,
PRBool aHasPseudoParent)
/* static */
const nsCSSFrameConstructor::FrameConstructionData*
nsCSSFrameConstructor::FindDataByInt(PRInt32 aInt,
nsIContent* aContent,
nsStyleContext* aStyleContext,
const FrameConstructionDataByInt* aDataPtr,
PRUint32 aDataLength)
{
for (const FrameConstructionDataByInt *curData = aDataPtr,
*endData = aDataPtr + aDataLength;
curData != endData;
++curData) {
if (curData->mInt == aInt) {
const FrameConstructionData* data = &curData->mData;
if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
return data->mFunc.mDataGetter(aContent, aStyleContext);
}
return data;
}
}
return nsnull;
}
/* static */
const nsCSSFrameConstructor::FrameConstructionData*
nsCSSFrameConstructor::FindDataByTag(nsIAtom* aTag,
nsIContent* aContent,
nsStyleContext* aStyleContext,
const FrameConstructionDataByTag* aDataPtr,
PRUint32 aDataLength)
{
for (const FrameConstructionDataByTag *curData = aDataPtr,
*endData = aDataPtr + aDataLength;
curData != endData;
++curData) {
if (*curData->mTag == aTag) {
const FrameConstructionData* data = &curData->mData;
if (data->mBits & FCDATA_FUNC_IS_DATA_GETTER) {
return data->mFunc.mDataGetter(aContent, aStyleContext);
}
return data;
}
}
return nsnull;
}
#define FCDATA_DECL(_flags, _func) \
{ _flags, { (FrameCreationFunc)_func } }
#define SIMPLE_FCDATA(_func) FCDATA_DECL(0, _func)
#define SIMPLE_INT_CREATE(_int, _func) { _int, SIMPLE_FCDATA(_func) }
#define SIMPLE_INT_CHAIN(_int, _func) \
{ _int, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) }
#define COMPLEX_INT_CREATE(_int, _func) \
{ _int, { FCDATA_FUNC_IS_FULL_CTOR, { nsnull }, _func } }
#define SIMPLE_TAG_CREATE(_tag, _func) \
{ &nsGkAtoms::_tag, SIMPLE_FCDATA(_func) }
#define SIMPLE_TAG_CHAIN(_tag, _func) \
{ &nsGkAtoms::_tag, FCDATA_DECL(FCDATA_FUNC_IS_DATA_GETTER, _func) }
#define COMPLEX_TAG_CREATE(_tag, _func) \
{ &nsGkAtoms::_tag, { FCDATA_FUNC_IS_FULL_CTOR, { nsnull }, _func } }
/* static */
const nsCSSFrameConstructor::FrameConstructionData*
nsCSSFrameConstructor::FindHTMLData(nsIContent* aContent,
nsIAtom* aTag,
PRInt32 aNameSpaceID,
nsStyleContext* aStyleContext)
{
// Ignore the tag if it's not HTML content and if it doesn't extend (via XBL)
// a valid HTML namespace. This check must match the one in
// ShouldHaveFirstLineStyle.
if (!aContent->IsNodeOfType(nsINode::eHTML) &&
aNameSpaceID != kNameSpaceID_XHTML) {
return nsnull;
}
static const FrameConstructionDataByTag sHTMLData[] = {
SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData),
SIMPLE_TAG_CHAIN(mozgeneratedcontentimage,
nsCSSFrameConstructor::FindImgData),
{ &nsGkAtoms::br, FCDATA_DECL(FCDATA_SKIP_FRAMEMAP, NS_NewBRFrame) },
SIMPLE_TAG_CREATE(wbr, NS_NewBRFrame),
SIMPLE_TAG_CHAIN(input, nsCSSFrameConstructor::FindInputData),
SIMPLE_TAG_CREATE(textarea, NS_NewTextControlFrame),
COMPLEX_TAG_CREATE(select, &nsCSSFrameConstructor::ConstructSelectFrame),
SIMPLE_TAG_CHAIN(object, nsCSSFrameConstructor::FindObjectData),
SIMPLE_TAG_CHAIN(applet, nsCSSFrameConstructor::FindObjectData),
SIMPLE_TAG_CHAIN(embed, nsCSSFrameConstructor::FindObjectData),
COMPLEX_TAG_CREATE(fieldset,
&nsCSSFrameConstructor::ConstructFieldSetFrame),
SIMPLE_TAG_CREATE(legend, NS_NewLegendFrame),
SIMPLE_TAG_CREATE(frameset, NS_NewHTMLFramesetFrame),
SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame),
SIMPLE_TAG_CREATE(spacer, NS_NewSpacerFrame),
COMPLEX_TAG_CREATE(button, &nsCSSFrameConstructor::ConstructButtonFrame),
SIMPLE_TAG_CREATE(canvas, NS_NewHTMLCanvasFrame),
#if defined(MOZ_MEDIA)
SIMPLE_TAG_CREATE(video, NS_NewHTMLVideoFrame),
SIMPLE_TAG_CREATE(audio, NS_NewHTMLVideoFrame),
#endif
SIMPLE_TAG_CREATE(isindex, NS_NewIsIndexFrame)
};
return FindDataByTag(aTag, aContent, aStyleContext, sHTMLData,
NS_ARRAY_LENGTH(sHTMLData));
}
/* static */
const nsCSSFrameConstructor::FrameConstructionData*
nsCSSFrameConstructor::FindImgData(nsIContent* aContent,
nsStyleContext* aStyleContext)
{
if (!nsImageFrame::ShouldCreateImageFrameFor(aContent, aStyleContext)) {
return nsnull;
}
static const FrameConstructionData sImgData = SIMPLE_FCDATA(NS_NewImageFrame);
return &sImgData;
}
/* static */
const nsCSSFrameConstructor::FrameConstructionData*
nsCSSFrameConstructor::FindImgControlData(nsIContent* aContent,
nsStyleContext* aStyleContext)
{
if (!nsImageFrame::ShouldCreateImageFrameFor(aContent, aStyleContext)) {
return nsnull;
}
static const FrameConstructionData sImgControlData =
SIMPLE_FCDATA(NS_NewImageControlFrame);
return &sImgControlData;
}
/* static */
const nsCSSFrameConstructor::FrameConstructionData*
nsCSSFrameConstructor::FindInputData(nsIContent* aContent,
nsStyleContext* aStyleContext)
{
static const FrameConstructionDataByInt sInputData[] = {
SIMPLE_INT_CREATE(NS_FORM_INPUT_CHECKBOX, NS_NewGfxCheckboxControlFrame),
SIMPLE_INT_CREATE(NS_FORM_INPUT_RADIO, NS_NewGfxRadioControlFrame),
SIMPLE_INT_CREATE(NS_FORM_INPUT_FILE, NS_NewFileControlFrame),
SIMPLE_INT_CHAIN(NS_FORM_INPUT_IMAGE,
nsCSSFrameConstructor::FindImgControlData),
SIMPLE_INT_CREATE(NS_FORM_INPUT_TEXT, NS_NewTextControlFrame),
SIMPLE_INT_CREATE(NS_FORM_INPUT_PASSWORD, NS_NewTextControlFrame),
COMPLEX_INT_CREATE(NS_FORM_INPUT_SUBMIT,
&nsCSSFrameConstructor::ConstructButtonFrame),
COMPLEX_INT_CREATE(NS_FORM_INPUT_RESET,
&nsCSSFrameConstructor::ConstructButtonFrame),
COMPLEX_INT_CREATE(NS_FORM_INPUT_BUTTON,
&nsCSSFrameConstructor::ConstructButtonFrame)
// Keeping hidden inputs out of here on purpose for so they get frames by
// display (in practice, none).
};
nsCOMPtr<nsIFormControl> control = do_QueryInterface(aContent);
NS_ASSERTION(control, "input doesn't implement nsIFormControl?");
return FindDataByInt(control->GetType(), aContent, aStyleContext,
sInputData, NS_ARRAY_LENGTH(sInputData));
}
/* static */
const nsCSSFrameConstructor::FrameConstructionData*
nsCSSFrameConstructor::FindObjectData(nsIContent* aContent,
nsStyleContext* aStyleContext)
{
// GetDisplayedType isn't necessarily nsIObjectLoadingContent::TYPE_NULL for
// cases when the object is broken/suppressed/etc (e.g. a broken image), but
// we want to treat those cases as TYPE_NULL
PRUint32 type;
if (aContent->IntrinsicState() &
(NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_USERDISABLED |
NS_EVENT_STATE_SUPPRESSED)) {
type = nsIObjectLoadingContent::TYPE_NULL;
} else {
nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(aContent));
NS_ASSERTION(objContent,
"applet, embed and object must implement "
"nsIObjectLoadingContent!");
objContent->GetDisplayedType(&type);
}
static const FrameConstructionDataByInt sObjectData[] = {
SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_LOADING,
NS_NewEmptyFrame),
SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_PLUGIN,
NS_NewObjectFrame),
SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_IMAGE,
NS_NewImageFrame),
SIMPLE_INT_CREATE(nsIObjectLoadingContent::TYPE_DOCUMENT,
NS_NewSubDocumentFrame)
// Nothing for TYPE_NULL so we'll construct frames by display there
};
return FindDataByInt((PRInt32)type, aContent, aStyleContext,
sObjectData, NS_ARRAY_LENGTH(sObjectData));
}
nsresult
nsCSSFrameConstructor::ConstructFrameFromData(const FrameConstructionData* aData,
nsFrameConstructorState& aState,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsIAtom* aTag,
nsStyleContext* aStyleContext,
nsFrameItems& aFrameItems,
PRBool aHasPseudoParent)
{
if (!aData) {
// nothing to do
return NS_OK;
}
PRBool frameHasBeenInitialized = PR_FALSE;
nsIFrame* newFrame = nsnull; // the frame we construct
PRBool addToHashTable = PR_TRUE;
PRBool addedToFrameList = PR_FALSE;
nsresult rv = NS_OK;
PRBool triedFrame = PR_FALSE;
PRUint32 bits = aData->mBits;
NS_ASSERTION(!(bits & FCDATA_FUNC_IS_DATA_GETTER),
"Should have dealt with this inside the data finder");
// We found something, so not creating by display type. Process
// pseudo-frames now.
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems);
}
// See if the element is absolute or fixed positioned
const nsStyleDisplay* display = aStyleContext->GetStyleDisplay();
// Create a frame based on the tag
if (nsGkAtoms::img == aTag || nsGkAtoms::mozgeneratedcontentimage == aTag) {
// Make sure to keep IsSpecialContent in synch with this code
rv = CreateHTMLImageFrame(aContent, aStyleContext, NS_NewImageFrame,
&newFrame);
if (newFrame) {
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems);
}
}
}
else if (nsGkAtoms::br == aTag) {
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems);
}
newFrame = NS_NewBRFrame(mPresShell, aStyleContext);
triedFrame = PR_TRUE;
// BR frames don't go in the content->frame hash table: typically
// there are many BR content objects and this would increase the size
// of the hash table, and it's doubtful we need the mapping anyway
addToHashTable = PR_FALSE;
}
else if (nsGkAtoms::wbr == aTag) {
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems);
}
newFrame = NS_NewWBRFrame(mPresShell, aStyleContext);
triedFrame = PR_TRUE;
}
else if (nsGkAtoms::input == aTag) {
// Make sure to keep IsSpecialContent in synch with this code
rv = CreateInputFrame(aState, aContent, aParentFrame,
aTag, aStyleContext, &newFrame,
display, frameHasBeenInitialized,
addedToFrameList, aFrameItems,
aHasPseudoParent);
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty() &&
newFrame && !addedToFrameList) {
// We'll still be adding this new frame, and it's a replaced
// element, so process pseudo-frames now.
ProcessPseudoFrames(aState, aFrameItems);
}
}
else if (nsGkAtoms::textarea == aTag) {
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems);
}
newFrame = NS_NewTextControlFrame(mPresShell, aStyleContext);
triedFrame = PR_TRUE;
}
else if (nsGkAtoms::select == aTag) {
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems);
}
rv = ConstructSelectFrame(aState, aContent, aParentFrame,
aTag, aStyleContext, newFrame,
display, frameHasBeenInitialized,
aFrameItems);
if (newFrame) {
NS_ASSERTION(nsPlaceholderFrame::GetRealFrameFor(aFrameItems.lastChild) ==
newFrame,
"Frame didn't get added to aFrameItems?");
addedToFrameList = PR_TRUE;
}
}
else if (nsGkAtoms::object == aTag ||
nsGkAtoms::applet == aTag ||
nsGkAtoms::embed == aTag) {
// Make sure to keep IsSpecialContent in synch with this code
if (!(aContent->IntrinsicState() &
(NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_USERDISABLED |
NS_EVENT_STATE_SUPPRESSED))) {
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems);
}
nsCOMPtr<nsIObjectLoadingContent> objContent(do_QueryInterface(aContent));
NS_ASSERTION(objContent,
"applet, embed and object must implement nsIObjectLoadingContent!");
if (!objContent) {
// XBL might trigger this...
return NS_ERROR_UNEXPECTED;
}
PRUint32 type;
objContent->GetDisplayedType(&type);
if (type == nsIObjectLoadingContent::TYPE_LOADING) {
// Ideally, this should show the standby attribute
// XXX Should we return something that is replaced, or make
// nsFrame replaced but not its subclasses?
newFrame = NS_NewEmptyFrame(mPresShell, aStyleContext);
}
else if (type == nsIObjectLoadingContent::TYPE_PLUGIN)
newFrame = NS_NewObjectFrame(mPresShell, aStyleContext);
else if (type == nsIObjectLoadingContent::TYPE_IMAGE)
newFrame = NS_NewImageFrame(mPresShell, aStyleContext);
else if (type == nsIObjectLoadingContent::TYPE_DOCUMENT)
newFrame = NS_NewSubDocumentFrame(mPresShell, aStyleContext);
#ifdef DEBUG
else
NS_ERROR("Shouldn't get here if we're not broken and not "
"suppressed and not blocked");
#endif
triedFrame = PR_TRUE;
}
}
else if (nsGkAtoms::fieldset == aTag) {
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems);
}
rv = ConstructFieldSetFrame(aState, aContent, aParentFrame,
aTag, aStyleContext, newFrame,
aFrameItems, display, frameHasBeenInitialized);
NS_ASSERTION(nsPlaceholderFrame::GetRealFrameFor(aFrameItems.lastChild) ==
newFrame,
"Frame didn't get added to aFrameItems?");
addedToFrameList = PR_TRUE;
}
else if (nsGkAtoms::legend == aTag) {
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems);
}
newFrame = NS_NewLegendFrame(mPresShell, aStyleContext);
triedFrame = PR_TRUE;
}
else if (nsGkAtoms::frameset == aTag) {
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems);
}
newFrame = NS_NewHTMLFramesetFrame(mPresShell, aStyleContext);
triedFrame = PR_TRUE;
}
else if (nsGkAtoms::iframe == aTag) {
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems);
}
newFrame = NS_NewSubDocumentFrame(mPresShell, aStyleContext);
triedFrame = PR_TRUE;
}
else if (nsGkAtoms::spacer == aTag) {
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems);
}
newFrame = NS_NewSpacerFrame(mPresShell, aStyleContext);
triedFrame = PR_TRUE;
}
else if (nsGkAtoms::button == aTag) {
rv = ConstructButtonFrame(aState, aContent, aParentFrame,
aTag, aStyleContext, &newFrame,
display, aFrameItems, aHasPseudoParent);
// the html4 button needs to act just like a
// regular button except contain html content
// so it must be replaced or html outside it will
// draw into its borders. -EDV
frameHasBeenInitialized = PR_TRUE;
addedToFrameList = PR_TRUE;
}
else if (nsGkAtoms::isindex == aTag) {
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems);
}
newFrame = NS_NewIsIndexFrame(mPresShell, aStyleContext);
triedFrame = PR_TRUE;
}
else if (nsGkAtoms::canvas == aTag) {
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems);
}
newFrame = NS_NewHTMLCanvasFrame(mPresShell, aStyleContext);
triedFrame = PR_TRUE;
}
#if defined(MOZ_MEDIA)
else if (nsGkAtoms::video == aTag || nsGkAtoms::audio == aTag) {
// We create video frames for audio elements so we can show controls.
// Note that html.css specifies display:none for audio elements
// without the "controls" attribute.
if (!aHasPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aState, aFrameItems);
}
newFrame = NS_NewHTMLVideoFrame(mPresShell, aStyleContext);
triedFrame = PR_TRUE;
}
#endif
if (NS_UNLIKELY(triedFrame && !newFrame)) {
return NS_ERROR_OUT_OF_MEMORY;
}
else if (NS_FAILED(rv) || !newFrame) {
return rv;
}
// If we succeeded in creating a frame then initialize it, process its
// children (if requested), and set the initial child list
// Note: at this point we should construct kids for newFrame only if
// it's not a leaf and hasn't been initialized yet.
if (!frameHasBeenInitialized) {
NS_ASSERTION(!addedToFrameList,
"Frames that were already added to the frame list should be "
"initialized by now!");
nsIFrame* geometricParent = aState.GetGeometricParent(display,
aParentFrame);
rv = InitAndRestoreFrame(aState, aContent, geometricParent, nsnull, newFrame);
NS_ASSERTION(NS_SUCCEEDED(rv), "InitAndRestoreFrame failed");
// See if we need to create a view
nsHTMLContainerFrame::CreateViewForFrame(newFrame, PR_FALSE);
rv = aState.AddChild(newFrame, aFrameItems, aContent, aStyleContext,
aParentFrame);
nsIFrame* newFrame;
if (bits & FCDATA_FUNC_IS_FULL_CTOR) {
nsresult rv =
(this->*(aData->mFullConstructor))(aState, aContent, aParentFrame,
aTag, aStyleContext, display,
aFrameItems, &newFrame);
if (NS_FAILED(rv)) {
return rv;
}
addedToFrameList = PR_TRUE;
} else {
newFrame =
(*aData->mFunc.mCreationFunc)(mPresShell, aStyleContext);
if (!newFrame) {
return NS_ERROR_OUT_OF_MEMORY;
}
PRBool allowOutOfFlow = !(bits & FCDATA_DISALLOW_OUT_OF_FLOW);
nsIFrame* geometricParent =
allowOutOfFlow ? aState.GetGeometricParent(display, aParentFrame)
: aParentFrame;
nsresult rv = InitAndRestoreFrame(aState, aContent, geometricParent, nsnull,
newFrame);
NS_ASSERTION(NS_SUCCEEDED(rv), "InitAndRestoreFrame failed");
// See whether we need to create a view
nsHTMLContainerFrame::CreateViewForFrame(newFrame, PR_FALSE);
rv = aState.AddChild(newFrame, aFrameItems, aContent, aStyleContext,
aParentFrame, allowOutOfFlow, allowOutOfFlow);
if (NS_FAILED(rv)) {
return rv;
}
// Process the child content if requested
nsFrameItems childItems;
nsFrameConstructorSaveState absoluteSaveState;
if (display->IsPositioned()) {
if (bits & FCDATA_FORCE_NULL_ABSPOS_CONTAINER) {
aState.PushAbsoluteContainingBlock(nsnull, absoluteSaveState);
} else if (display->IsPositioned()) {
aState.PushAbsoluteContainingBlock(newFrame, absoluteSaveState);
}
@ -5433,25 +5291,11 @@ nsCSSFrameConstructor::ConstructHTMLFrame(nsFrameConstructorState& aState,
newFrame->SetInitialChildList(nsnull, childItems.childList);
}
if (!addedToFrameList) {
// Gotta do it here. Note that things like absolutely positioned replaced
// elements and the like will end up in this code. So use the AddChild
// on the state.
rv = aState.AddChild(newFrame, aFrameItems, aContent, aStyleContext,
aParentFrame);
if (NS_FAILED(rv)) {
return rv;
}
}
if (addToHashTable) {
// Add a mapping from content object to primary frame. Note that for
// floated and positioned frames this is the out-of-flow frame and not
// the placeholder frame
if (!(bits & FCDATA_SKIP_FRAMEMAP)) {
aState.mFrameManager->SetPrimaryFrameFor(aContent, newFrame);
}
return rv;
return NS_OK;
}
nsresult
@ -7280,8 +7124,10 @@ nsCSSFrameConstructor::ConstructFrameInternal( nsFrameConstructorState& aState,
nsIFrame* lastChild = frameItems->lastChild;
// Handle specific frame types
rv = ConstructHTMLFrame(aState, aContent, adjParentFrame, aTag, aNameSpaceID,
styleContext, *frameItems, pseudoParent);
rv = ConstructFrameFromData(FindHTMLData(aContent, aTag, aNameSpaceID,
styleContext),
aState, aContent, adjParentFrame, aTag,
styleContext, *frameItems, pseudoParent);
// Failing to find a matching HTML frame, try creating a specialized
// XUL frame. This is temporary, pending planned factoring of this
@ -10999,7 +10845,7 @@ nsCSSFrameConstructor::ShouldHaveFirstLineStyle(nsIContent* aContent,
PRInt32 namespaceID;
nsIAtom* tag = mDocument->BindingManager()->ResolveTag(aContent,
&namespaceID);
// This check must match the one in ConstructHTMLFrame.
// This check must match the one in FindHTMLData.
hasFirstLine = tag != nsGkAtoms::fieldset ||
(namespaceID != kNameSpaceID_XHTML &&
!aContent->IsNodeOfType(nsINode::eHTML));

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

@ -512,6 +512,139 @@ private:
nsIFrame*& aParentFrame,
PRBool& aIsPseudoParent);
private:
/* A constructor function that just creates an nsIFrame object. The caller
is responsible for initializing the object, adding it to frame lists,
constructing frames for the children, etc.
@param nsIPresShell the presshell whose arena should be used to allocate
the frame.
@param nsStyleContext the style context to use for the frame. */
typedef nsIFrame* (* FrameCreationFunc)(nsIPresShell*, nsStyleContext*);
/* A function that can be used to get a FrameConstructionData. Such
a function is allowed to return null.
@param nsIContent the node for which the frame is being constructed.
@param nsStyleContext the style context to be used for the frame.
*/
struct FrameConstructionData;
typedef const FrameConstructionData*
(* FrameConstructionDataGetter)(nsIContent*, nsStyleContext*);
/* A constructor function that's used for complicated construction tasks.
This is expected to create the new frame, initialize it, add whatever
needs to be added to aFrameItems (XXXbz is that really necessary? Could
caller add? Might there be cases when *aNewFrame or its placeholder is
not the thing that ends up in aFrameItems? If not, would it be safe to do
the add into the frame construction state after processing kids? Look
into this as a followup!), process children as needed, etc. It is NOT
expected to deal with the primary frame map.
@param aState the frame construction state to use.
@param aContent the content node to construct the frame for.
@param aParentFrame the frame to set as the parent of the
newly-constructed frame.
@param aTag the content's XBL-resolved tag.
@param aStyleContext the style context to use for the new frame.
@param aFrameItems the frame list to add the new frame (or its
placeholder) to.
@param aFrame out param handing out the frame that was constructed. This
frame is what the caller will add to the primary frame map.
*/
typedef nsresult
(nsCSSFrameConstructor::* FrameFullConstructor)(nsFrameConstructorState& aState,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsIAtom* aTag,
nsStyleContext* aStyleContext,
const nsStyleDisplay* aStyleDisplay,
nsFrameItems& aFrameItems,
nsIFrame** aFrame);
/* Bits that modify the way a FrameConstructionData is handled */
/* If the FCDATA_SKIP_FRAMEMAP bit is set, then the frame created should not
be added to the primary frame map */
#define FCDATA_SKIP_FRAMEMAP 0x1
/* If the FCDATA_FUNC_IS_DATA_GETTER bit is set, then the mFunc of the
FrameConstructionData is a getter function that can be used to get the
actual FrameConstructionData to use. */
#define FCDATA_FUNC_IS_DATA_GETTER 0x2
/* If the FCDATA_FUNC_IS_FULL_CTOR bit is set, then the FrameConstructionData
has an mFullConstructor. In this case, there is no relevant mData or
mFunc */
#define FCDATA_FUNC_IS_FULL_CTOR 0x4
/* If FCDATA_DISALLOW_OUT_OF_FLOW is set, do not allow the frame to
float or be absolutely positioned. This cannot be used with
FCDATA_FUNC_IS_FULL_CTOR */
#define FCDATA_DISALLOW_OUT_OF_FLOW 0x8
/* If FCDATA_FORCE_NULL_ABSPOS_CONTAINER is set, make sure to push a
null absolute containing block before processing children for this
frame. If this is not set, the frame will be pushed as the
absolute containing block as needed, based on its style */
#define FCDATA_FORCE_NULL_ABSPOS_CONTAINER 0x10
/* Structure representing information about how a frame should be
constructed. */
struct FrameConstructionData {
// Flag bits that can modify the way the construction happens
PRUint32 mBits;
// We have exactly one of three types of functions, so use a union for
// better cache locality for the ones that aren't pointer-to-member. That
// one needs to be separate, because we can't cast between it and the
// others and hence wouldn't be able to initialize the union without a
// constructor and all the resulting generated code. See documentation
// above for FrameCreationFunc, FrameConstructionDataGetter, and
// FrameFullConstructor to see what the functions would do.
union Func {
FrameCreationFunc mCreationFunc;
FrameConstructionDataGetter mDataGetter;
} mFunc;
FrameFullConstructor mFullConstructor;
};
/* Structure representing a mapping of an atom to a FrameConstructionData.
This can be used with non-static atoms, assuming that the nsIAtom* is
stored somewhere that this struct can point to (that is, a static
nsIAtom*) and that it's allocated before the struct is ever used. */
struct FrameConstructionDataByTag {
// Pointer to nsIAtom* is used because we want to initialize this
// statically, so before our atom tables are set up.
const nsIAtom * const * const mTag;
const FrameConstructionData mData;
};
/* Structure representing a mapping of an integer to a
FrameConstructionData. There are no magic integer values here. */
struct FrameConstructionDataByInt {
/* Could be used for display or whatever else */
const PRInt32 mInt;
const FrameConstructionData mData;
};
/* A function that takes an integer, content, style context, and array of
FrameConstructionDataByInts and finds the appropriate frame construction
data to use and returns it. This can return null if none of the integers
match or if the matching integer has a FrameConstructionDataGetter that
returns null. */
static const FrameConstructionData*
FindDataByInt(PRInt32 aInt, nsIContent* aContent,
nsStyleContext* aStyleContext,
const FrameConstructionDataByInt* aDataPtr,
PRUint32 aDataLength);
/* A function that takes a tag, content, style context, and array of
FrameConstructionDataByTags and finds the appropriate frame construction
data to use and returns it. This can return null if none of the tags
match or if the matching tag has a FrameConstructionDataGetter that
returns null. */
static const FrameConstructionData*
FindDataByTag(nsIAtom* aTag, nsIContent* aContent,
nsStyleContext* aStyleContext,
const FrameConstructionDataByTag* aDataPtr,
PRUint32 aDataLength);
/**
* Function to adjust aParentFrame and aFrameItems to deal with table
* pseudo-frames that may have to be inserted.
@ -547,8 +680,6 @@ private:
PRBool& aSuppressFrame,
PRBool& aCreatedPseudo);
const nsStyleDisplay* GetDisplay(nsIFrame* aFrame);
// END TABLE SECTION
protected:
@ -568,10 +699,9 @@ private:
nsIFrame* aParentFrame,
nsIAtom* aTag,
nsStyleContext* aStyleContext,
nsIFrame** aNewFrame,
const nsStyleDisplay* aStyleDisplay,
nsFrameItems& aFrameItems,
PRBool aHasPseudoParent);
nsIFrame** aNewFrame);
// ConstructSelectFrame puts the new frame in aFrameItems and
// handles the kids of the select.
@ -580,10 +710,9 @@ private:
nsIFrame* aParentFrame,
nsIAtom* aTag,
nsStyleContext* aStyleContext,
nsIFrame*& aNewFrame,
const nsStyleDisplay* aStyleDisplay,
PRBool& aFrameHasBeenInitialized,
nsFrameItems& aFrameItems);
nsFrameItems& aFrameItems,
nsIFrame** aNewFrame);
// ConstructFieldSetFrame puts the new frame in aFrameItems and
// handles the kids of the fieldset
@ -592,10 +721,9 @@ private:
nsIFrame* aParentFrame,
nsIAtom* aTag,
nsStyleContext* aStyleContext,
nsIFrame*& aNewFrame,
nsFrameItems& aFrameItems,
const nsStyleDisplay* aStyleDisplay,
PRBool& aFrameHasBeenInitialized);
nsFrameItems& aFrameItems,
nsIFrame** aNewFrame);
nsresult ConstructTextFrame(nsFrameConstructorState& aState,
nsIContent* aContent,
@ -619,14 +747,50 @@ private:
nsStyleContext* aStyleContext,
nsFrameItems& aFrameItems);
nsresult ConstructHTMLFrame(nsFrameConstructorState& aState,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsIAtom* aTag,
PRInt32 aNameSpaceID,
nsStyleContext* aStyleContext,
nsFrameItems& aFrameItems,
PRBool aHasPseudoParent);
static PRBool IsSpecialContent(nsIContent* aContent,
nsIAtom* aTag,
PRInt32 aNameSpaceID,
nsStyleContext* aStyleContext);
// Function to find FrameConstructionData for aContent. Will return
// null if aContent is not HTML.
static const FrameConstructionData* FindHTMLData(nsIContent* aContent,
nsIAtom* aTag,
PRInt32 aNameSpaceID,
nsStyleContext* aStyleContext);
// HTML data-finding helper functions
static const FrameConstructionData*
FindImgData(nsIContent* aContent, nsStyleContext* aStyleContext);
static const FrameConstructionData*
FindImgControlData(nsIContent* aContent, nsStyleContext* aStyleContext);
static const FrameConstructionData*
FindInputData(nsIContent* aContent, nsStyleContext* aStyleContext);
static const FrameConstructionData*
FindObjectData(nsIContent* aContent, nsStyleContext* aStyleContext);
/* Construct a frame from the given FrameConstructionData. This function
will handle adding the frame to frame lists, processing children, adding
it to the primary frame map, and so forth.
@param aData the FrameConstructionData to use.
@param aState the frame construction state to use.
@param aContent the content node to construct the frame for.
@param aParentFrame the frame to set as the parent of the
newly-constructed frame.
@param aTag the content's XBL-resolved tag.
@param aStyleContext the style context to use for the new frame.
@param aFrameItems the frame list to add the new frame (or its
placeholder) to.
@param aHasPseudoParent whether aParentFrame is a table pseudo-frame.
*/
nsresult ConstructFrameFromData(const FrameConstructionData* aData,
nsFrameConstructorState& aState,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsIAtom* aTag,
nsStyleContext* aStyleContext,
nsFrameItems& aFrameItems,
PRBool aHasPseudoParent);
nsresult ConstructFrameInternal( nsFrameConstructorState& aState,
nsIContent* aContent,
@ -743,33 +907,6 @@ private:
nsFrameItems& aFrameItems,
PRBool aAllowBlockStyles);
// @param OUT aFrame the newly created frame
nsresult CreateInputFrame(nsFrameConstructorState& aState,
nsIContent* aContent,
nsIFrame* aParentFrame,
nsIAtom* aTag,
nsStyleContext* aStyleContext,
nsIFrame** aFrame,
const nsStyleDisplay* aStyleDisplay,
PRBool& aFrameHasBeenInitialized,
PRBool& aAddedToFrameList,
nsFrameItems& aFrameItems,
PRBool aHasPseudoParent);
// A function that can be invoked to create some sort of image frame.
typedef nsIFrame* (* ImageFrameCreatorFunc)(nsIPresShell*, nsStyleContext*);
/**
* CreateHTMLImageFrame will do some tests on aContent, and if it determines
* that the content should get an image frame it'll create one via aFunc and
* return it in *aFrame. Note that if this content node isn't supposed to
* have an image frame this method will return NS_OK and set *aFrame to null.
*/
nsresult CreateHTMLImageFrame(nsIContent* aContent,
nsStyleContext* aStyleContext,
ImageFrameCreatorFunc aFunc,
nsIFrame** aFrame);
nsIFrame* GetFrameFor(nsIContent* aContent);
/**