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 "core/rendering/InlineBox.h" 25 #include "core/rendering/RenderOverflow.h" 26 #include "core/rendering/style/ShadowData.h" 27 28 namespace WebCore { 29 30 class HitTestRequest; 31 class HitTestResult; 32 class InlineTextBox; 33 class RenderLineBoxList; 34 class SimpleFontData; 35 class VerticalPositionCache; 36 37 struct GlyphOverflow; 38 39 typedef HashMap<const InlineTextBox*, pair<Vector<const SimpleFontData*>, GlyphOverflow> > GlyphOverflowAndFallbackFontsMap; 40 41 class InlineFlowBox : public InlineBox { 42 public: 43 InlineFlowBox(RenderObject* obj) 44 : InlineBox(obj) 45 , m_firstChild(0) 46 , m_lastChild(0) 47 , m_prevLineBox(0) 48 , m_nextLineBox(0) 49 , m_includeLogicalLeftEdge(false) 50 , m_includeLogicalRightEdge(false) 51 , m_descendantsHaveSameLineHeightAndBaseline(true) 52 , m_baselineType(AlphabeticBaseline) 53 , m_hasAnnotationsBefore(false) 54 , m_hasAnnotationsAfter(false) 55 #ifndef NDEBUG 56 , m_hasBadChildList(false) 57 #endif 58 { 59 // 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 60 // 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 61 // an invisible marker exists. The side effect of having an invisible marker is that the quirks mode behavior of shrinking lines with no 62 // text children must not apply. This change also means that gaps will exist between image bullet list items. Even when the list bullet 63 // is an image, the line is still considered to be immune from the quirk. 64 m_hasTextChildren = obj->style()->display() == LIST_ITEM; 65 m_hasTextDescendants = m_hasTextChildren; 66 } 67 68 #ifndef NDEBUG 69 virtual ~InlineFlowBox(); 70 71 virtual void showLineTreeAndMark(const InlineBox* = 0, const char* = 0, const InlineBox* = 0, const char* = 0, const RenderObject* = 0, int = 0) const; 72 virtual const char* boxName() const; 73 #endif 74 75 InlineFlowBox* prevLineBox() const { return m_prevLineBox; } 76 InlineFlowBox* nextLineBox() const { return m_nextLineBox; } 77 void setNextLineBox(InlineFlowBox* n) { m_nextLineBox = n; } 78 void setPreviousLineBox(InlineFlowBox* p) { m_prevLineBox = p; } 79 80 InlineBox* firstChild() const { checkConsistency(); return m_firstChild; } 81 InlineBox* lastChild() const { checkConsistency(); return m_lastChild; } 82 83 virtual bool isLeaf() const OVERRIDE FINAL { return false; } 84 85 InlineBox* firstLeafChild() const; 86 InlineBox* lastLeafChild() const; 87 88 typedef void (*CustomInlineBoxRangeReverse)(void* userData, Vector<InlineBox*>::iterator first, Vector<InlineBox*>::iterator last); 89 void collectLeafBoxesInLogicalOrder(Vector<InlineBox*>&, CustomInlineBoxRangeReverse customReverseImplementation = 0, void* userData = 0) const; 90 91 virtual void setConstructed() OVERRIDE FINAL 92 { 93 InlineBox::setConstructed(); 94 for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) 95 child->setConstructed(); 96 } 97 98 void addToLine(InlineBox* child); 99 virtual void deleteLine() OVERRIDE FINAL; 100 virtual void extractLine() OVERRIDE FINAL; 101 virtual void attachLine() OVERRIDE FINAL; 102 virtual void adjustPosition(float dx, float dy); 103 104 virtual void extractLineBoxFromRenderObject(); 105 virtual void attachLineBoxToRenderObject(); 106 virtual void removeLineBoxFromRenderObject(); 107 108 virtual void clearTruncation() OVERRIDE; 109 110 IntRect roundedFrameRect() const; 111 112 void paintBoxDecorations(PaintInfo&, const LayoutPoint&); 113 void paintMask(PaintInfo&, const LayoutPoint&); 114 void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver); 115 void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver); 116 void paintBoxShadow(const PaintInfo&, RenderStyle*, ShadowStyle, const LayoutRect&); 117 virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); 118 virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; 119 120 bool boxShadowCanBeAppliedToBackground(const FillLayer&) const; 121 122 virtual RenderLineBoxList* rendererLineBoxes() const; 123 124 // logicalLeft = left in a horizontal line and top in a vertical line. 125 LayoutUnit marginBorderPaddingLogicalLeft() const { return marginLogicalLeft() + borderLogicalLeft() + paddingLogicalLeft(); } 126 LayoutUnit marginBorderPaddingLogicalRight() const { return marginLogicalRight() + borderLogicalRight() + paddingLogicalRight(); } 127 LayoutUnit marginLogicalLeft() const 128 { 129 if (!includeLogicalLeftEdge()) 130 return 0; 131 return isHorizontal() ? boxModelObject()->marginLeft() : boxModelObject()->marginTop(); 132 } 133 LayoutUnit marginLogicalRight() const 134 { 135 if (!includeLogicalRightEdge()) 136 return 0; 137 return isHorizontal() ? boxModelObject()->marginRight() : boxModelObject()->marginBottom(); 138 } 139 int borderLogicalLeft() const 140 { 141 if (!includeLogicalLeftEdge()) 142 return 0; 143 return isHorizontal() ? renderer()->style(isFirstLineStyle())->borderLeftWidth() : renderer()->style(isFirstLineStyle())->borderTopWidth(); 144 } 145 int borderLogicalRight() const 146 { 147 if (!includeLogicalRightEdge()) 148 return 0; 149 return isHorizontal() ? renderer()->style(isFirstLineStyle())->borderRightWidth() : renderer()->style(isFirstLineStyle())->borderBottomWidth(); 150 } 151 int paddingLogicalLeft() const 152 { 153 if (!includeLogicalLeftEdge()) 154 return 0; 155 return isHorizontal() ? boxModelObject()->paddingLeft() : boxModelObject()->paddingTop(); 156 } 157 int paddingLogicalRight() const 158 { 159 if (!includeLogicalRightEdge()) 160 return 0; 161 return isHorizontal() ? boxModelObject()->paddingRight() : boxModelObject()->paddingBottom(); 162 } 163 164 bool includeLogicalLeftEdge() const { return m_includeLogicalLeftEdge; } 165 bool includeLogicalRightEdge() const { return m_includeLogicalRightEdge; } 166 void setEdges(bool includeLeft, bool includeRight) 167 { 168 m_includeLogicalLeftEdge = includeLeft; 169 m_includeLogicalRightEdge = includeRight; 170 } 171 172 // Helper functions used during line construction and placement. 173 void determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer); 174 LayoutUnit getFlowSpacingLogicalWidth(); 175 float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&); 176 float placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild, float& logicalLeft, float& minLogicalLeft, float& maxLogicalRight, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&); 177 void beginPlacingBoxRangesInInlineDirection(float logicalLeft) { setLogicalLeft(logicalLeft); } 178 void endPlacingBoxRangesInInlineDirection(float logicalLeft, float logicalRight, float minLogicalLeft, float maxLogicalRight) 179 { 180 setLogicalWidth(logicalRight - logicalLeft); 181 if (knownToHaveNoOverflow() && (minLogicalLeft < logicalLeft || maxLogicalRight > logicalRight)) 182 clearKnownToHaveNoOverflow(); 183 } 184 185 void computeLogicalBoxHeights(RootInlineBox*, LayoutUnit& maxPositionTop, LayoutUnit& maxPositionBottom, 186 int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent, 187 bool strictMode, GlyphOverflowAndFallbackFontsMap&, FontBaseline, VerticalPositionCache&); 188 void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, 189 int maxPositionTop, int maxPositionBottom); 190 void placeBoxesInBlockDirection(LayoutUnit logicalTop, LayoutUnit maxHeight, int maxAscent, bool strictMode, LayoutUnit& lineTop, LayoutUnit& lineBottom, bool& setLineTop, 191 LayoutUnit& lineTopIncludingMargins, LayoutUnit& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline); 192 void flipLinesInBlockDirection(LayoutUnit lineTop, LayoutUnit lineBottom); 193 bool requiresIdeographicBaseline(const GlyphOverflowAndFallbackFontsMap&) const; 194 195 LayoutUnit computeOverAnnotationAdjustment(LayoutUnit allowedPosition) const; 196 LayoutUnit computeUnderAnnotationAdjustment(LayoutUnit allowedPosition) const; 197 198 void computeOverflow(LayoutUnit lineTop, LayoutUnit lineBottom, GlyphOverflowAndFallbackFontsMap&); 199 200 void removeChild(InlineBox* child); 201 202 virtual RenderObject::SelectionState selectionState(); 203 204 virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const OVERRIDE FINAL; 205 virtual float placeEllipsisBox(bool ltr, float blockLeftEdge, float blockRightEdge, float ellipsisWidth, float &truncatedWidth, bool&) OVERRIDE; 206 207 bool hasTextChildren() const { return m_hasTextChildren; } 208 bool hasTextDescendants() const { return m_hasTextDescendants; } 209 void setHasTextChildren() { m_hasTextChildren = true; setHasTextDescendants(); } 210 void setHasTextDescendants() { m_hasTextDescendants = true; } 211 212 void checkConsistency() const; 213 void setHasBadChildList(); 214 215 // Line visual and layout overflow are in the coordinate space of the block. This means that they aren't purely physical directions. 216 // For horizontal-tb and vertical-lr they will match physical directions, but for horizontal-bt and vertical-rl, the top/bottom and left/right 217 // 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. 218 LayoutRect layoutOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const 219 { 220 return m_overflow ? m_overflow->layoutOverflowRect() : enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom)); 221 } 222 LayoutUnit logicalLeftLayoutOverflow() const 223 { 224 return m_overflow ? (isHorizontal() ? m_overflow->layoutOverflowRect().x() : m_overflow->layoutOverflowRect().y()) : 225 static_cast<LayoutUnit>(logicalLeft()); 226 } 227 LayoutUnit logicalRightLayoutOverflow() const 228 { 229 return m_overflow ? (isHorizontal() ? m_overflow->layoutOverflowRect().maxX() : m_overflow->layoutOverflowRect().maxY()) : 230 static_cast<LayoutUnit>(ceilf(logicalRight())); 231 } 232 LayoutUnit logicalTopLayoutOverflow(LayoutUnit lineTop) const 233 { 234 if (m_overflow) 235 return isHorizontal() ? m_overflow->layoutOverflowRect().y() : m_overflow->layoutOverflowRect().x(); 236 return lineTop; 237 } 238 LayoutUnit logicalBottomLayoutOverflow(LayoutUnit lineBottom) const 239 { 240 if (m_overflow) 241 return isHorizontal() ? m_overflow->layoutOverflowRect().maxY() : m_overflow->layoutOverflowRect().maxX(); 242 return lineBottom; 243 } 244 LayoutRect logicalLayoutOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const 245 { 246 LayoutRect result = layoutOverflowRect(lineTop, lineBottom); 247 if (!renderer()->isHorizontalWritingMode()) 248 result = result.transposedRect(); 249 return result; 250 } 251 252 LayoutRect visualOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const 253 { 254 return m_overflow ? m_overflow->visualOverflowRect() : enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom)); 255 } 256 LayoutUnit logicalLeftVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->visualOverflowRect().x() : m_overflow->visualOverflowRect().y()) : static_cast<LayoutUnit>(logicalLeft()); } 257 LayoutUnit logicalRightVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->visualOverflowRect().maxX() : m_overflow->visualOverflowRect().maxY()) : static_cast<LayoutUnit>(ceilf(logicalRight())); } 258 LayoutUnit logicalTopVisualOverflow(LayoutUnit lineTop) const 259 { 260 if (m_overflow) 261 return isHorizontal() ? m_overflow->visualOverflowRect().y() : m_overflow->visualOverflowRect().x(); 262 return lineTop; 263 } 264 LayoutUnit logicalBottomVisualOverflow(LayoutUnit lineBottom) const 265 { 266 if (m_overflow) 267 return isHorizontal() ? m_overflow->visualOverflowRect().maxY() : m_overflow->visualOverflowRect().maxX(); 268 return lineBottom; 269 } 270 LayoutRect logicalVisualOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const 271 { 272 LayoutRect result = visualOverflowRect(lineTop, lineBottom); 273 if (!renderer()->isHorizontalWritingMode()) 274 result = result.transposedRect(); 275 return result; 276 } 277 278 void setOverflowFromLogicalRects(const LayoutRect& logicalLayoutOverflow, const LayoutRect& logicalVisualOverflow, LayoutUnit lineTop, LayoutUnit lineBottom); 279 void setLayoutOverflow(const LayoutRect&, LayoutUnit lineTop, LayoutUnit lineBottom); 280 void setVisualOverflow(const LayoutRect&, LayoutUnit lineTop, LayoutUnit lineBottom); 281 282 FloatRect frameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const 283 { 284 if (isHorizontal()) 285 return FloatRect(m_topLeft.x(), lineTop, width(), lineBottom - lineTop); 286 return FloatRect(lineTop, m_topLeft.y(), lineBottom - lineTop, height()); 287 } 288 289 FloatRect logicalFrameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const 290 { 291 return FloatRect(logicalLeft(), lineTop, logicalWidth(), lineBottom - lineTop); 292 } 293 294 bool descendantsHaveSameLineHeightAndBaseline() const { return m_descendantsHaveSameLineHeightAndBaseline; } 295 void clearDescendantsHaveSameLineHeightAndBaseline() 296 { 297 m_descendantsHaveSameLineHeightAndBaseline = false; 298 if (parent() && parent()->descendantsHaveSameLineHeightAndBaseline()) 299 parent()->clearDescendantsHaveSameLineHeightAndBaseline(); 300 } 301 302 private: 303 void addBoxShadowVisualOverflow(LayoutRect& logicalVisualOverflow); 304 void addBorderOutsetVisualOverflow(LayoutRect& logicalVisualOverflow); 305 void addTextBoxVisualOverflow(InlineTextBox*, GlyphOverflowAndFallbackFontsMap&, LayoutRect& logicalVisualOverflow); 306 void addReplacedChildOverflow(const InlineBox*, LayoutRect& logicalLayoutOverflow, LayoutRect& logicalVisualOverflow); 307 void constrainToLineTopAndBottomIfNeeded(LayoutRect&) const; 308 309 protected: 310 OwnPtr<RenderOverflow> m_overflow; 311 312 virtual bool isInlineFlowBox() const OVERRIDE FINAL { return true; } 313 314 InlineBox* m_firstChild; 315 InlineBox* m_lastChild; 316 317 InlineFlowBox* m_prevLineBox; // The previous box that also uses our RenderObject 318 InlineFlowBox* m_nextLineBox; // The next box that also uses our RenderObject 319 320 #if ENABLE(CSS3_TEXT) 321 // Maximum logicalTop among all children of an InlineFlowBox. Used to 322 // calculate the offset for TextUnderlinePositionUnder. 323 void computeMaxLogicalTop(float& maxLogicalTop) const; 324 #endif // CSS3_TEXT 325 private: 326 unsigned m_includeLogicalLeftEdge : 1; 327 unsigned m_includeLogicalRightEdge : 1; 328 unsigned m_hasTextChildren : 1; 329 unsigned m_hasTextDescendants : 1; 330 unsigned m_descendantsHaveSameLineHeightAndBaseline : 1; 331 332 protected: 333 // The following members are only used by RootInlineBox but moved here to keep the bits packed. 334 335 // Whether or not this line uses alphabetic or ideographic baselines by default. 336 unsigned m_baselineType : 1; // FontBaseline 337 338 // If the line contains any ruby runs, then this will be true. 339 unsigned m_hasAnnotationsBefore : 1; 340 unsigned m_hasAnnotationsAfter : 1; 341 342 unsigned m_lineBreakBidiStatusEor : 5; // WTF::Unicode::Direction 343 unsigned m_lineBreakBidiStatusLastStrong : 5; // WTF::Unicode::Direction 344 unsigned m_lineBreakBidiStatusLast : 5; // WTF::Unicode::Direction 345 346 // End of RootInlineBox-specific members. 347 348 #ifndef NDEBUG 349 private: 350 unsigned m_hasBadChildList : 1; 351 #endif 352 }; 353 354 inline InlineFlowBox* toInlineFlowBox(InlineBox* object) 355 { 356 ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isInlineFlowBox()); 357 return static_cast<InlineFlowBox*>(object); 358 } 359 360 inline const InlineFlowBox* toInlineFlowBox(const InlineBox* object) 361 { 362 ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isInlineFlowBox()); 363 return static_cast<const InlineFlowBox*>(object); 364 } 365 366 // This will catch anyone doing an unnecessary cast. 367 void toInlineFlowBox(const InlineFlowBox*); 368 369 #ifdef NDEBUG 370 inline void InlineFlowBox::checkConsistency() const 371 { 372 } 373 #endif 374 375 inline void InlineFlowBox::setHasBadChildList() 376 { 377 #ifndef NDEBUG 378 m_hasBadChildList = true; 379 #endif 380 } 381 382 } // namespace WebCore 383 384 #ifndef NDEBUG 385 // Outside the WebCore namespace for ease of invocation from gdb. 386 void showTree(const WebCore::InlineFlowBox*); 387 #endif 388 389 #endif // InlineFlowBox_h 390