1 /* 2 * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 * 19 */ 20 21 #ifndef InlineFlowBox_h 22 #define InlineFlowBox_h 23 24 #include "InlineBox.h" 25 #include "RenderOverflow.h" 26 #include "ShadowData.h" 27 28 namespace WebCore { 29 30 class HitTestRequest; 31 class HitTestResult; 32 class InlineTextBox; 33 class RenderLineBoxList; 34 class VerticalPositionCache; 35 36 typedef HashMap<const InlineTextBox*, pair<Vector<const SimpleFontData*>, GlyphOverflow> > GlyphOverflowAndFallbackFontsMap; 37 38 class InlineFlowBox : public InlineBox { 39 public: 40 InlineFlowBox(RenderObject* obj) 41 : InlineBox(obj) 42 , m_firstChild(0) 43 , m_lastChild(0) 44 , m_prevLineBox(0) 45 , m_nextLineBox(0) 46 , m_includeLogicalLeftEdge(false) 47 , m_includeLogicalRightEdge(false) 48 , m_descendantsHaveSameLineHeightAndBaseline(true) 49 #ifndef NDEBUG 50 , m_hasBadChildList(false) 51 #endif 52 { 53 // 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 54 // 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 55 // an invisible marker exists. The side effect of having an invisible marker is that the quirks mode behavior of shrinking lines with no 56 // text children must not apply. This change also means that gaps will exist between image bullet list items. Even when the list bullet 57 // is an image, the line is still considered to be immune from the quirk. 58 m_hasTextChildren = obj->style()->display() == LIST_ITEM; 59 m_hasTextDescendants = m_hasTextChildren; 60 } 61 62 #ifndef NDEBUG 63 virtual ~InlineFlowBox(); 64 #endif 65 66 InlineFlowBox* prevLineBox() const { return m_prevLineBox; } 67 InlineFlowBox* nextLineBox() const { return m_nextLineBox; } 68 void setNextLineBox(InlineFlowBox* n) { m_nextLineBox = n; } 69 void setPreviousLineBox(InlineFlowBox* p) { m_prevLineBox = p; } 70 71 InlineBox* firstChild() const { checkConsistency(); return m_firstChild; } 72 InlineBox* lastChild() const { checkConsistency(); return m_lastChild; } 73 74 virtual bool isLeaf() const { return false; } 75 76 InlineBox* firstLeafChild() const; 77 InlineBox* lastLeafChild() const; 78 79 typedef void (*CustomInlineBoxRangeReverse)(void* userData, Vector<InlineBox*>::iterator first, Vector<InlineBox*>::iterator last); 80 void collectLeafBoxesInLogicalOrder(Vector<InlineBox*>&, CustomInlineBoxRangeReverse customReverseImplementation = 0, void* userData = 0) const; 81 82 virtual void setConstructed() 83 { 84 InlineBox::setConstructed(); 85 for (InlineBox* child = firstChild(); child; child = child->next()) 86 child->setConstructed(); 87 } 88 89 void addToLine(InlineBox* child); 90 virtual void deleteLine(RenderArena*); 91 virtual void extractLine(); 92 virtual void attachLine(); 93 virtual void adjustPosition(float dx, float dy); 94 95 virtual void extractLineBoxFromRenderObject(); 96 virtual void attachLineBoxToRenderObject(); 97 virtual void removeLineBoxFromRenderObject(); 98 99 virtual void clearTruncation(); 100 101 IntRect roundedFrameRect() const; 102 103 virtual void paintBoxDecorations(PaintInfo&, int tx, int ty); 104 virtual void paintMask(PaintInfo&, int tx, int ty); 105 void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver); 106 void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, int tx, int ty, int w, int h, CompositeOperator = CompositeSourceOver); 107 void paintBoxShadow(GraphicsContext*, RenderStyle*, ShadowStyle, int tx, int ty, int w, int h); 108 virtual void paint(PaintInfo&, int tx, int ty, int lineTop, int lineBottom); 109 virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, int lineTop, int lineBottom); 110 111 virtual RenderLineBoxList* rendererLineBoxes() const; 112 113 // logicalLeft = left in a horizontal line and top in a vertical line. 114 int marginBorderPaddingLogicalLeft() const { return marginLogicalLeft() + borderLogicalLeft() + paddingLogicalLeft(); } 115 int marginBorderPaddingLogicalRight() const { return marginLogicalRight() + borderLogicalRight() + paddingLogicalRight(); } 116 int marginLogicalLeft() const 117 { 118 if (!includeLogicalLeftEdge()) 119 return 0; 120 return isHorizontal() ? boxModelObject()->marginLeft() : boxModelObject()->marginTop(); 121 } 122 int marginLogicalRight() const 123 { 124 if (!includeLogicalRightEdge()) 125 return 0; 126 return isHorizontal() ? boxModelObject()->marginRight() : boxModelObject()->marginBottom(); 127 } 128 int borderLogicalLeft() const 129 { 130 if (!includeLogicalLeftEdge()) 131 return 0; 132 return isHorizontal() ? renderer()->style()->borderLeftWidth() : renderer()->style()->borderTopWidth(); 133 } 134 int borderLogicalRight() const 135 { 136 if (!includeLogicalRightEdge()) 137 return 0; 138 return isHorizontal() ? renderer()->style()->borderRightWidth() : renderer()->style()->borderBottomWidth(); 139 } 140 int paddingLogicalLeft() const 141 { 142 if (!includeLogicalLeftEdge()) 143 return 0; 144 return isHorizontal() ? boxModelObject()->paddingLeft() : boxModelObject()->paddingTop(); 145 } 146 int paddingLogicalRight() const 147 { 148 if (!includeLogicalRightEdge()) 149 return 0; 150 return isHorizontal() ? boxModelObject()->paddingRight() : boxModelObject()->paddingBottom(); 151 } 152 153 bool includeLogicalLeftEdge() const { return m_includeLogicalLeftEdge; } 154 bool includeLogicalRightEdge() const { return m_includeLogicalRightEdge; } 155 void setEdges(bool includeLeft, bool includeRight) 156 { 157 m_includeLogicalLeftEdge = includeLeft; 158 m_includeLogicalRightEdge = includeRight; 159 } 160 161 // Helper functions used during line construction and placement. 162 void determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer); 163 int getFlowSpacingLogicalWidth(); 164 float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&); 165 void computeLogicalBoxHeights(RootInlineBox*, int& maxPositionTop, int& maxPositionBottom, 166 int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent, 167 bool strictMode, GlyphOverflowAndFallbackFontsMap&, FontBaseline, VerticalPositionCache&); 168 void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, 169 int maxPositionTop, int maxPositionBottom); 170 void placeBoxesInBlockDirection(int logicalTop, int maxHeight, int maxAscent, bool strictMode, int& lineTop, int& lineBottom, bool& setLineTop, 171 int& lineTopIncludingMargins, int& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline); 172 void flipLinesInBlockDirection(int lineTop, int lineBottom); 173 bool requiresIdeographicBaseline(const GlyphOverflowAndFallbackFontsMap&) const; 174 175 int computeOverAnnotationAdjustment(int allowedPosition) const; 176 int computeUnderAnnotationAdjustment(int allowedPosition) const; 177 178 void computeOverflow(int lineTop, int lineBottom, GlyphOverflowAndFallbackFontsMap&); 179 180 void removeChild(InlineBox* child); 181 182 virtual RenderObject::SelectionState selectionState(); 183 184 virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth); 185 virtual float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, bool&); 186 187 bool hasTextChildren() const { return m_hasTextChildren; } 188 bool hasTextDescendants() const { return m_hasTextDescendants; } 189 190 void checkConsistency() const; 191 void setHasBadChildList(); 192 193 // Line visual and layout overflow are in the coordinate space of the block. This means that they aren't purely physical directions. 194 // For horizontal-tb and vertical-lr they will match physical directions, but for horizontal-bt and vertical-rl, the top/bottom and left/right 195 // 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. 196 IntRect layoutOverflowRect(int lineTop, int lineBottom) const 197 { 198 return m_overflow ? m_overflow->layoutOverflowRect() : enclosingIntRect(frameRectIncludingLineHeight(lineTop, lineBottom)); 199 } 200 int logicalLeftLayoutOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->minXLayoutOverflow() : m_overflow->minYLayoutOverflow()) : logicalLeft(); } 201 int logicalRightLayoutOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->maxXLayoutOverflow() : m_overflow->maxYLayoutOverflow()) : ceilf(logicalRight()); } 202 int logicalTopLayoutOverflow(int lineTop) const 203 { 204 if (m_overflow) 205 return isHorizontal() ? m_overflow->minYLayoutOverflow() : m_overflow->minXLayoutOverflow(); 206 return lineTop; 207 } 208 int logicalBottomLayoutOverflow(int lineBottom) const 209 { 210 if (m_overflow) 211 return isHorizontal() ? m_overflow->maxYLayoutOverflow() : m_overflow->maxXLayoutOverflow(); 212 return lineBottom; 213 } 214 IntRect logicalLayoutOverflowRect(int lineTop, int lineBottom) const 215 { 216 IntRect result = layoutOverflowRect(lineTop, lineBottom); 217 if (!renderer()->isHorizontalWritingMode()) 218 result = result.transposedRect(); 219 return result; 220 } 221 222 IntRect visualOverflowRect(int lineTop, int lineBottom) const 223 { 224 return m_overflow ? m_overflow->visualOverflowRect() : enclosingIntRect(frameRectIncludingLineHeight(lineTop, lineBottom)); 225 } 226 int logicalLeftVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->minXVisualOverflow() : m_overflow->minYVisualOverflow()) : logicalLeft(); } 227 int logicalRightVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->maxXVisualOverflow() : m_overflow->maxYVisualOverflow()) : ceilf(logicalRight()); } 228 int logicalTopVisualOverflow(int lineTop) const 229 { 230 if (m_overflow) 231 return isHorizontal() ? m_overflow->minYVisualOverflow() : m_overflow->minXVisualOverflow(); 232 return lineTop; 233 } 234 int logicalBottomVisualOverflow(int lineBottom) const 235 { 236 if (m_overflow) 237 return isHorizontal() ? m_overflow->maxYVisualOverflow() : m_overflow->maxXVisualOverflow(); 238 return lineBottom; 239 } 240 IntRect logicalVisualOverflowRect(int lineTop, int lineBottom) const 241 { 242 IntRect result = visualOverflowRect(lineTop, lineBottom); 243 if (!renderer()->isHorizontalWritingMode()) 244 result = result.transposedRect(); 245 return result; 246 } 247 248 void setOverflowFromLogicalRects(const IntRect& logicalLayoutOverflow, const IntRect& logicalVisualOverflow, int lineTop, int lineBottom); 249 void setLayoutOverflow(const IntRect&, int lineTop, int lineBottom); 250 void setVisualOverflow(const IntRect&, int lineTop, int lineBottom); 251 252 FloatRect frameRectIncludingLineHeight(int lineTop, int lineBottom) const 253 { 254 if (isHorizontal()) 255 return FloatRect(m_x, lineTop, width(), lineBottom - lineTop); 256 return FloatRect(lineTop, m_y, lineBottom - lineTop, height()); 257 } 258 259 FloatRect logicalFrameRectIncludingLineHeight(int lineTop, int lineBottom) const 260 { 261 return FloatRect(logicalLeft(), lineTop, logicalWidth(), lineBottom - lineTop); 262 } 263 264 bool descendantsHaveSameLineHeightAndBaseline() const { return m_descendantsHaveSameLineHeightAndBaseline; } 265 void clearDescendantsHaveSameLineHeightAndBaseline() 266 { 267 m_descendantsHaveSameLineHeightAndBaseline = false; 268 if (parent() && parent()->descendantsHaveSameLineHeightAndBaseline()) 269 parent()->clearDescendantsHaveSameLineHeightAndBaseline(); 270 } 271 272 private: 273 void addBoxShadowVisualOverflow(IntRect& logicalVisualOverflow); 274 void addTextBoxVisualOverflow(InlineTextBox*, GlyphOverflowAndFallbackFontsMap&, IntRect& logicalVisualOverflow); 275 void addReplacedChildOverflow(const InlineBox*, IntRect& logicalLayoutOverflow, IntRect& logicalVisualOverflow); 276 277 protected: 278 OwnPtr<RenderOverflow> m_overflow; 279 280 virtual bool isInlineFlowBox() const { return true; } 281 282 InlineBox* m_firstChild; 283 InlineBox* m_lastChild; 284 285 InlineFlowBox* m_prevLineBox; // The previous box that also uses our RenderObject 286 InlineFlowBox* m_nextLineBox; // The next box that also uses our RenderObject 287 288 bool m_includeLogicalLeftEdge : 1; 289 bool m_includeLogicalRightEdge : 1; 290 bool m_hasTextChildren : 1; 291 bool m_hasTextDescendants : 1; 292 bool m_descendantsHaveSameLineHeightAndBaseline : 1; 293 294 #ifndef NDEBUG 295 bool m_hasBadChildList; 296 #endif 297 }; 298 299 #ifdef NDEBUG 300 inline void InlineFlowBox::checkConsistency() const 301 { 302 } 303 #endif 304 305 inline void InlineFlowBox::setHasBadChildList() 306 { 307 #ifndef NDEBUG 308 m_hasBadChildList = true; 309 #endif 310 } 311 312 } // namespace WebCore 313 314 #ifndef NDEBUG 315 // Outside the WebCore namespace for ease of invocation from gdb. 316 void showTree(const WebCore::InlineFlowBox*); 317 #endif 318 319 #endif // InlineFlowBox_h 320