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: