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