/* * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #ifndef InlineFlowBox_h #define InlineFlowBox_h #include "InlineBox.h" #include "RenderOverflow.h" #include "ShadowData.h" namespace WebCore { class HitTestRequest; class HitTestResult; class InlineTextBox; class RenderLineBoxList; class VerticalPositionCache; typedef HashMap<const InlineTextBox*, pair<Vector<const SimpleFontData*>, GlyphOverflow> > GlyphOverflowAndFallbackFontsMap; class InlineFlowBox : public InlineBox { public: InlineFlowBox(RenderObject* obj) : InlineBox(obj) , m_firstChild(0) , m_lastChild(0) , m_prevLineBox(0) , m_nextLineBox(0) , m_includeLogicalLeftEdge(false) , m_includeLogicalRightEdge(false) , m_descendantsHaveSameLineHeightAndBaseline(true) #ifndef NDEBUG , m_hasBadChildList(false) #endif { // Internet Explorer and Firefox always create a marker for list items, even when the list-style-type is none. We do not make a marker // in the list-style-type: none case, since it is wasteful to do so. However, in order to match other browsers we have to pretend like // an invisible marker exists. The side effect of having an invisible marker is that the quirks mode behavior of shrinking lines with no // text children must not apply. This change also means that gaps will exist between image bullet list items. Even when the list bullet // is an image, the line is still considered to be immune from the quirk. m_hasTextChildren = obj->style()->display() == LIST_ITEM; m_hasTextDescendants = m_hasTextChildren; } #ifndef NDEBUG virtual ~InlineFlowBox(); #endif InlineFlowBox* prevLineBox() const { return m_prevLineBox; } InlineFlowBox* nextLineBox() const { return m_nextLineBox; } void setNextLineBox(InlineFlowBox* n) { m_nextLineBox = n; } void setPreviousLineBox(InlineFlowBox* p) { m_prevLineBox = p; } InlineBox* firstChild() const { checkConsistency(); return m_firstChild; } InlineBox* lastChild() const { checkConsistency(); return m_lastChild; } virtual bool isLeaf() const { return false; } InlineBox* firstLeafChild() const; InlineBox* lastLeafChild() const; typedef void (*CustomInlineBoxRangeReverse)(void* userData, Vector<InlineBox*>::iterator first, Vector<InlineBox*>::iterator last); void collectLeafBoxesInLogicalOrder(Vector<InlineBox*>&, CustomInlineBoxRangeReverse customReverseImplementation = 0, void* userData = 0) const; virtual void setConstructed() { InlineBox::setConstructed(); for (InlineBox* child = firstChild(); child; child = child->next()) child->setConstructed(); } void addToLine(InlineBox* child); virtual void deleteLine(RenderArena*); virtual void extractLine(); virtual void attachLine(); virtual void adjustPosition(float dx, float dy); virtual void extractLineBoxFromRenderObject(); virtual void attachLineBoxToRenderObject(); virtual void removeLineBoxFromRenderObject(); virtual void clearTruncation(); IntRect roundedFrameRect() const; virtual void paintBoxDecorations(PaintInfo&, int tx, int ty); virtual void paintMask(PaintInfo&, int tx, int ty); void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver); void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver); void paintBoxShadow(GraphicsContext*, RenderStyle*, ShadowStyle, int tx, int ty, int w, int h); virtual void paint(PaintInfo&, int tx, int ty, int lineTop, int lineBottom); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, int lineTop, int lineBottom); virtual RenderLineBoxList* rendererLineBoxes() const; // logicalLeft = left in a horizontal line and top in a vertical line. int marginBorderPaddingLogicalLeft() const { return marginLogicalLeft() + borderLogicalLeft() + paddingLogicalLeft(); } int marginBorderPaddingLogicalRight() const { return marginLogicalRight() + borderLogicalRight() + paddingLogicalRight(); } int marginLogicalLeft() const { if (!includeLogicalLeftEdge()) return 0; return isHorizontal() ? boxModelObject()->marginLeft() : boxModelObject()->marginTop(); } int marginLogicalRight() const { if (!includeLogicalRightEdge()) return 0; return isHorizontal() ? boxModelObject()->marginRight() : boxModelObject()->marginBottom(); } int borderLogicalLeft() const { if (!includeLogicalLeftEdge()) return 0; return isHorizontal() ? renderer()->style()->borderLeftWidth() : renderer()->style()->borderTopWidth(); } int borderLogicalRight() const { if (!includeLogicalRightEdge()) return 0; return isHorizontal() ? renderer()->style()->borderRightWidth() : renderer()->style()->borderBottomWidth(); } int paddingLogicalLeft() const { if (!includeLogicalLeftEdge()) return 0; return isHorizontal() ? boxModelObject()->paddingLeft() : boxModelObject()->paddingTop(); } int paddingLogicalRight() const { if (!includeLogicalRightEdge()) return 0; return isHorizontal() ? boxModelObject()->paddingRight() : boxModelObject()->paddingBottom(); } bool includeLogicalLeftEdge() const { return m_includeLogicalLeftEdge; } bool includeLogicalRightEdge() const { return m_includeLogicalRightEdge; } void setEdges(bool includeLeft, bool includeRight) { m_includeLogicalLeftEdge = includeLeft; m_includeLogicalRightEdge = includeRight; } // Helper functions used during line construction and placement. void determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer); int getFlowSpacingLogicalWidth(); float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&); void computeLogicalBoxHeights(RootInlineBox*, int& maxPositionTop, int& maxPositionBottom, int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent, bool strictMode, GlyphOverflowAndFallbackFontsMap&, FontBaseline, VerticalPositionCache&); void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, int maxPositionTop, int maxPositionBottom); void placeBoxesInBlockDirection(int logicalTop, int maxHeight, int maxAscent, bool strictMode, int& lineTop, int& lineBottom, bool& setLineTop, int& lineTopIncludingMargins, int& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline); void flipLinesInBlockDirection(int lineTop, int lineBottom); bool requiresIdeographicBaseline(const GlyphOverflowAndFallbackFontsMap&) const; int computeOverAnnotationAdjustment(int allowedPosition) const; int computeUnderAnnotationAdjustment(int allowedPosition) const; void computeOverflow(int lineTop, int lineBottom, GlyphOverflowAndFallbackFontsMap&); void removeChild(InlineBox* child); virtual RenderObject::SelectionState selectionState(); virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth); virtual float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, bool&); bool hasTextChildren() const { return m_hasTextChildren; } bool hasTextDescendants() const { return m_hasTextDescendants; } void checkConsistency() const; void setHasBadChildList(); // Line visual and layout overflow are in the coordinate space of the block. This means that they aren't purely physical directions. // For horizontal-tb and vertical-lr they will match physical directions, but for horizontal-bt and vertical-rl, the top/bottom and left/right // respectively are flipped when compared to their physical counterparts. For example minX is on the left in vertical-lr, but it is on the right in vertical-rl. IntRect layoutOverflowRect(int lineTop, int lineBottom) const { return m_overflow ? m_overflow->layoutOverflowRect() : enclosingIntRect(frameRectIncludingLineHeight(lineTop, lineBottom)); } int logicalLeftLayoutOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->minXLayoutOverflow() : m_overflow->minYLayoutOverflow()) : logicalLeft(); } int logicalRightLayoutOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->maxXLayoutOverflow() : m_overflow->maxYLayoutOverflow()) : ceilf(logicalRight()); } int logicalTopLayoutOverflow(int lineTop) const { if (m_overflow) return isHorizontal() ? m_overflow->minYLayoutOverflow() : m_overflow->minXLayoutOverflow(); return lineTop; } int logicalBottomLayoutOverflow(int lineBottom) const { if (m_overflow) return isHorizontal() ? m_overflow->maxYLayoutOverflow() : m_overflow->maxXLayoutOverflow(); return lineBottom; } IntRect logicalLayoutOverflowRect(int lineTop, int lineBottom) const { IntRect result = layoutOverflowRect(lineTop, lineBottom); if (!renderer()->isHorizontalWritingMode()) result = result.transposedRect(); return result; } IntRect visualOverflowRect(int lineTop, int lineBottom) const { return m_overflow ? m_overflow->visualOverflowRect() : enclosingIntRect(frameRectIncludingLineHeight(lineTop, lineBottom)); } int logicalLeftVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->minXVisualOverflow() : m_overflow->minYVisualOverflow()) : logicalLeft(); } int logicalRightVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->maxXVisualOverflow() : m_overflow->maxYVisualOverflow()) : ceilf(logicalRight()); } int logicalTopVisualOverflow(int lineTop) const { if (m_overflow) return isHorizontal() ? m_overflow->minYVisualOverflow() : m_overflow->minXVisualOverflow(); return lineTop; } int logicalBottomVisualOverflow(int lineBottom) const { if (m_overflow) return isHorizontal() ? m_overflow->maxYVisualOverflow() : m_overflow->maxXVisualOverflow(); return lineBottom; } IntRect logicalVisualOverflowRect(int lineTop, int lineBottom) const { IntRect result = visualOverflowRect(lineTop, lineBottom); if (!renderer()->isHorizontalWritingMode()) result = result.transposedRect(); return result; } void setOverflowFromLogicalRects(const IntRect& logicalLayoutOverflow, const IntRect& logicalVisualOverflow, int lineTop, int lineBottom); void setLayoutOverflow(const IntRect&, int lineTop, int lineBottom); void setVisualOverflow(const IntRect&, int lineTop, int lineBottom); FloatRect frameRectIncludingLineHeight(int lineTop, int lineBottom) const { if (isHorizontal()) return FloatRect(m_x, lineTop, width(), lineBottom - lineTop); return FloatRect(lineTop, m_y, lineBottom - lineTop, height()); } FloatRect logicalFrameRectIncludingLineHeight(int lineTop, int lineBottom) const { return FloatRect(logicalLeft(), lineTop, logicalWidth(), lineBottom - lineTop); } bool descendantsHaveSameLineHeightAndBaseline() const { return m_descendantsHaveSameLineHeightAndBaseline; } void clearDescendantsHaveSameLineHeightAndBaseline() { m_descendantsHaveSameLineHeightAndBaseline = false; if (parent() && parent()->descendantsHaveSameLineHeightAndBaseline()) parent()->clearDescendantsHaveSameLineHeightAndBaseline(); } private: void addBoxShadowVisualOverflow(IntRect& logicalVisualOverflow); void addTextBoxVisualOverflow(InlineTextBox*, GlyphOverflowAndFallbackFontsMap&, IntRect& logicalVisualOverflow); void addReplacedChildOverflow(const InlineBox*, IntRect& logicalLayoutOverflow, IntRect& logicalVisualOverflow); protected: OwnPtr<RenderOverflow> m_overflow; virtual bool isInlineFlowBox() const { return true; } InlineBox* m_firstChild; InlineBox* m_lastChild; InlineFlowBox* m_prevLineBox; // The previous box that also uses our RenderObject InlineFlowBox* m_nextLineBox; // The next box that also uses our RenderObject bool m_includeLogicalLeftEdge : 1; bool m_includeLogicalRightEdge : 1; bool m_hasTextChildren : 1; bool m_hasTextDescendants : 1; bool m_descendantsHaveSameLineHeightAndBaseline : 1; #ifndef NDEBUG bool m_hasBadChildList; #endif }; #ifdef NDEBUG inline void InlineFlowBox::checkConsistency() const { } #endif inline void InlineFlowBox::setHasBadChildList() { #ifndef NDEBUG m_hasBadChildList = true; #endif } } // namespace WebCore #ifndef NDEBUG // Outside the WebCore namespace for ease of invocation from gdb. void showTree(const WebCore::InlineFlowBox*); #endif #endif // InlineFlowBox_h