michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* rendering object for HTML
elements */ michael@0: michael@0: #include "nsCOMPtr.h" michael@0: #include "nsFrame.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsLineLayout.h" michael@0: #include "nsStyleConsts.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsRenderingContext.h" michael@0: #include "nsLayoutUtils.h" michael@0: michael@0: //FOR SELECTION michael@0: #include "nsIContent.h" michael@0: //END INCLUDES FOR SELECTION michael@0: michael@0: using namespace mozilla; michael@0: michael@0: class BRFrame : public nsFrame { michael@0: public: michael@0: NS_DECL_FRAMEARENA_HELPERS michael@0: michael@0: friend nsIFrame* NS_NewBRFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); michael@0: michael@0: virtual ContentOffsets CalcContentOffsetsFromFramePoint(nsPoint aPoint) MOZ_OVERRIDE; michael@0: michael@0: virtual FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset) MOZ_OVERRIDE; michael@0: virtual FrameSearchResult PeekOffsetCharacter(bool aForward, int32_t* aOffset, michael@0: bool aRespectClusters = true) MOZ_OVERRIDE; michael@0: virtual FrameSearchResult PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, michael@0: bool aIsKeyboardSelect, int32_t* aOffset, michael@0: PeekWordState* aState) MOZ_OVERRIDE; michael@0: michael@0: virtual nsresult Reflow(nsPresContext* aPresContext, michael@0: nsHTMLReflowMetrics& aDesiredSize, michael@0: const nsHTMLReflowState& aReflowState, michael@0: nsReflowStatus& aStatus) MOZ_OVERRIDE; michael@0: virtual void AddInlineMinWidth(nsRenderingContext *aRenderingContext, michael@0: InlineMinWidthData *aData) MOZ_OVERRIDE; michael@0: virtual void AddInlinePrefWidth(nsRenderingContext *aRenderingContext, michael@0: InlinePrefWidthData *aData) MOZ_OVERRIDE; michael@0: virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; michael@0: virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; michael@0: virtual nsIAtom* GetType() const MOZ_OVERRIDE; michael@0: virtual nscoord GetBaseline() const MOZ_OVERRIDE; michael@0: michael@0: virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE michael@0: { michael@0: return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced | michael@0: nsIFrame::eLineParticipant)); michael@0: } michael@0: michael@0: #ifdef ACCESSIBILITY michael@0: virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE; michael@0: #endif michael@0: michael@0: protected: michael@0: BRFrame(nsStyleContext* aContext) : nsFrame(aContext) {} michael@0: virtual ~BRFrame(); michael@0: michael@0: nscoord mAscent; michael@0: }; michael@0: michael@0: nsIFrame* michael@0: NS_NewBRFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) michael@0: { michael@0: return new (aPresShell) BRFrame(aContext); michael@0: } michael@0: michael@0: NS_IMPL_FRAMEARENA_HELPERS(BRFrame) michael@0: michael@0: BRFrame::~BRFrame() michael@0: { michael@0: } michael@0: michael@0: nsresult michael@0: BRFrame::Reflow(nsPresContext* aPresContext, michael@0: nsHTMLReflowMetrics& aMetrics, michael@0: const nsHTMLReflowState& aReflowState, michael@0: nsReflowStatus& aStatus) michael@0: { michael@0: DO_GLOBAL_REFLOW_COUNT("BRFrame"); michael@0: DISPLAY_REFLOW(aPresContext, this, aReflowState, aMetrics, aStatus); michael@0: aMetrics.Height() = 0; // BR frames with height 0 are ignored in quirks michael@0: // mode by nsLineLayout::VerticalAlignFrames . michael@0: // However, it's not always 0. See below. michael@0: aMetrics.Width() = 0; michael@0: aMetrics.SetTopAscent(0); michael@0: michael@0: // Only when the BR is operating in a line-layout situation will it michael@0: // behave like a BR. michael@0: nsLineLayout* ll = aReflowState.mLineLayout; michael@0: if (ll) { michael@0: // Note that the compatibility mode check excludes AlmostStandards michael@0: // mode, since this is the inline box model. See bug 161691. michael@0: if ( ll->LineIsEmpty() || michael@0: aPresContext->CompatibilityMode() == eCompatibility_FullStandards ) { michael@0: // The line is logically empty; any whitespace is trimmed away. michael@0: // michael@0: // If this frame is going to terminate the line we know michael@0: // that nothing else will go on the line. Therefore, in this michael@0: // case, we provide some height for the BR frame so that it michael@0: // creates some vertical whitespace. It's necessary to use the michael@0: // line-height rather than the font size because the michael@0: // quirks-mode fix that doesn't apply the block's min michael@0: // line-height makes this necessary to make BR cause a line michael@0: // of the full line-height michael@0: michael@0: // We also do this in strict mode because BR should act like a michael@0: // normal inline frame. That line-height is used is important michael@0: // here for cases where the line-height is less than 1. michael@0: nsRefPtr fm; michael@0: nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), michael@0: nsLayoutUtils::FontSizeInflationFor(this)); michael@0: aReflowState.rendContext->SetFont(fm); // FIXME: maybe not needed? michael@0: if (fm) { michael@0: nscoord logicalHeight = aReflowState.CalcLineHeight(); michael@0: aMetrics.Height() = logicalHeight; michael@0: aMetrics.SetTopAscent(nsLayoutUtils::GetCenteredFontBaseline(fm, logicalHeight)); michael@0: } michael@0: else { michael@0: aMetrics.SetTopAscent(aMetrics.Height() = 0); michael@0: } michael@0: michael@0: // XXX temporary until I figure out a better solution; see the michael@0: // code in nsLineLayout::VerticalAlignFrames that zaps minY/maxY michael@0: // if the width is zero. michael@0: // XXX This also fixes bug 10036! michael@0: // Warning: nsTextControlFrame::CalculateSizeStandard depends on michael@0: // the following line, see bug 228752. michael@0: aMetrics.Width() = 1; michael@0: } michael@0: michael@0: // Return our reflow status michael@0: uint32_t breakType = aReflowState.mStyleDisplay->mBreakType; michael@0: if (NS_STYLE_CLEAR_NONE == breakType) { michael@0: breakType = NS_STYLE_CLEAR_LINE; michael@0: } michael@0: michael@0: aStatus = NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER | michael@0: NS_INLINE_MAKE_BREAK_TYPE(breakType); michael@0: ll->SetLineEndsInBR(true); michael@0: } michael@0: else { michael@0: aStatus = NS_FRAME_COMPLETE; michael@0: } michael@0: michael@0: aMetrics.SetOverflowAreasToDesiredBounds(); michael@0: michael@0: mAscent = aMetrics.TopAscent(); michael@0: michael@0: NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* virtual */ void michael@0: BRFrame::AddInlineMinWidth(nsRenderingContext *aRenderingContext, michael@0: nsIFrame::InlineMinWidthData *aData) michael@0: { michael@0: aData->ForceBreak(aRenderingContext); michael@0: } michael@0: michael@0: /* virtual */ void michael@0: BRFrame::AddInlinePrefWidth(nsRenderingContext *aRenderingContext, michael@0: nsIFrame::InlinePrefWidthData *aData) michael@0: { michael@0: aData->ForceBreak(aRenderingContext); michael@0: } michael@0: michael@0: /* virtual */ nscoord michael@0: BRFrame::GetMinWidth(nsRenderingContext *aRenderingContext) michael@0: { michael@0: nscoord result = 0; michael@0: DISPLAY_MIN_WIDTH(this, result); michael@0: return result; michael@0: } michael@0: michael@0: /* virtual */ nscoord michael@0: BRFrame::GetPrefWidth(nsRenderingContext *aRenderingContext) michael@0: { michael@0: nscoord result = 0; michael@0: DISPLAY_PREF_WIDTH(this, result); michael@0: return result; michael@0: } michael@0: michael@0: nsIAtom* michael@0: BRFrame::GetType() const michael@0: { michael@0: return nsGkAtoms::brFrame; michael@0: } michael@0: michael@0: nscoord michael@0: BRFrame::GetBaseline() const michael@0: { michael@0: return mAscent; michael@0: } michael@0: michael@0: nsIFrame::ContentOffsets BRFrame::CalcContentOffsetsFromFramePoint(nsPoint aPoint) michael@0: { michael@0: ContentOffsets offsets; michael@0: offsets.content = mContent->GetParent(); michael@0: if (offsets.content) { michael@0: offsets.offset = offsets.content->IndexOf(mContent); michael@0: offsets.secondaryOffset = offsets.offset; michael@0: offsets.associateWithNext = true; michael@0: } michael@0: return offsets; michael@0: } michael@0: michael@0: nsIFrame::FrameSearchResult michael@0: BRFrame::PeekOffsetNoAmount(bool aForward, int32_t* aOffset) michael@0: { michael@0: NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range"); michael@0: int32_t startOffset = *aOffset; michael@0: // If we hit the end of a BR going backwards, go to its beginning and stay there. michael@0: if (!aForward && startOffset != 0) { michael@0: *aOffset = 0; michael@0: return FOUND; michael@0: } michael@0: // Otherwise, stop if we hit the beginning, continue (forward) if we hit the end. michael@0: return (startOffset == 0) ? FOUND : CONTINUE; michael@0: } michael@0: michael@0: nsIFrame::FrameSearchResult michael@0: BRFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset, michael@0: bool aRespectClusters) michael@0: { michael@0: NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range"); michael@0: // Keep going. The actual line jumping will stop us. michael@0: return CONTINUE; michael@0: } michael@0: michael@0: nsIFrame::FrameSearchResult michael@0: BRFrame::PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect, michael@0: int32_t* aOffset, PeekWordState* aState) michael@0: { michael@0: NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range"); michael@0: // Keep going. The actual line jumping will stop us. michael@0: return CONTINUE; michael@0: } michael@0: michael@0: #ifdef ACCESSIBILITY michael@0: a11y::AccType michael@0: BRFrame::AccessibleType() michael@0: { michael@0: nsIContent *parent = mContent->GetParent(); michael@0: if (parent && parent->IsRootOfNativeAnonymousSubtree() && michael@0: parent->GetChildCount() == 1) { michael@0: // This
is the only node in a text control, therefore it is the hacky michael@0: // "bogus node" used when there is no text in the control michael@0: return a11y::eNoType; michael@0: } michael@0: michael@0: return a11y::eHTMLBRType; michael@0: } michael@0: #endif michael@0: