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