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 28namespace WebCore { 29 30class HitTestRequest; 31class HitTestResult; 32class InlineTextBox; 33class RenderLineBoxList; 34class SimpleFontData; 35class VerticalPositionCache; 36 37struct GlyphOverflow; 38 39typedef HashMap<const InlineTextBox*, std::pair<Vector<const SimpleFontData*>, GlyphOverflow>> GlyphOverflowAndFallbackFontsMap; 40 41class InlineFlowBox : public InlineBox { 42public: 43 explicit InlineFlowBox(RenderBoxModelObject& renderer) 44 : InlineBox(renderer) 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_isFirstAfterPageBreak(false) 56#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED 57 , m_hasBadChildList(false) 58#endif 59 { 60 // 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 61 // 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 62 // an invisible marker exists. The side effect of having an invisible marker is that the quirks mode behavior of shrinking lines with no 63 // text children must not apply. This change also means that gaps will exist between image bullet list items. Even when the list bullet 64 // is an image, the line is still considered to be immune from the quirk. 65 m_hasTextChildren = renderer.style().display() == LIST_ITEM; 66 m_hasTextDescendants = m_hasTextChildren; 67 } 68 69#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED 70 virtual ~InlineFlowBox(); 71#endif 72 73#ifndef NDEBUG 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 RenderBoxModelObject& renderer() const { return toRenderBoxModelObject(InlineBox::renderer()); } 79 const RenderStyle& lineStyle() const { return isFirstLine() ? renderer().firstLineStyle() : renderer().style(); } 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 void paintBoxDecorations(PaintInfo&, const LayoutPoint&); 117 void paintMask(PaintInfo&, const LayoutPoint&); 118 void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver); 119 void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver); 120 void paintBoxShadow(const PaintInfo&, const RenderStyle&, ShadowStyle, const LayoutRect&); 121 virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) override; 122 virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) override; 123 124 bool boxShadowCanBeAppliedToBackground(const FillLayer&) const; 125 126 // logicalLeft = left in a horizontal line and top in a vertical line. 127 LayoutUnit marginBorderPaddingLogicalLeft() const { return marginLogicalLeft() + borderLogicalLeft() + paddingLogicalLeft(); } 128 LayoutUnit marginBorderPaddingLogicalRight() const { return marginLogicalRight() + borderLogicalRight() + paddingLogicalRight(); } 129 LayoutUnit marginLogicalLeft() const 130 { 131 if (!includeLogicalLeftEdge()) 132 return 0; 133 return isHorizontal() ? renderer().marginLeft() : renderer().marginTop(); 134 } 135 LayoutUnit marginLogicalRight() const 136 { 137 if (!includeLogicalRightEdge()) 138 return 0; 139 return isHorizontal() ? renderer().marginRight() : renderer().marginBottom(); 140 } 141 float borderLogicalLeft() const 142 { 143 if (!includeLogicalLeftEdge()) 144 return 0; 145 return isHorizontal() ? lineStyle().borderLeftWidth() : lineStyle().borderTopWidth(); 146 } 147 float borderLogicalRight() const 148 { 149 if (!includeLogicalRightEdge()) 150 return 0; 151 return isHorizontal() ? lineStyle().borderRightWidth() : lineStyle().borderBottomWidth(); 152 } 153 float paddingLogicalLeft() const 154 { 155 if (!includeLogicalLeftEdge()) 156 return 0; 157 return isHorizontal() ? renderer().paddingLeft() : renderer().paddingTop(); 158 } 159 float paddingLogicalRight() const 160 { 161 if (!includeLogicalRightEdge()) 162 return 0; 163 return isHorizontal() ? renderer().paddingRight() : renderer().paddingBottom(); 164 } 165 166 bool includeLogicalLeftEdge() const { return m_includeLogicalLeftEdge; } 167 bool includeLogicalRightEdge() const { return m_includeLogicalRightEdge; } 168 void setEdges(bool includeLeft, bool includeRight) 169 { 170 m_includeLogicalLeftEdge = includeLeft; 171 m_includeLogicalRightEdge = includeRight; 172 } 173 174 // Helper functions used during line construction and placement. 175 void determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, RenderObject* logicallyLastRunRenderer); 176 LayoutUnit getFlowSpacingLogicalWidth(); 177 float placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing); 178 float placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild, 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, 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); 203 204 virtual RenderObject::SelectionState selectionState() 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 logicalTopLayoutOverflow(LayoutUnit lineTop) const 225 { 226 if (m_overflow) 227 return isHorizontal() ? m_overflow->layoutOverflowRect().y() : m_overflow->layoutOverflowRect().x(); 228 return lineTop; 229 } 230 LayoutUnit logicalBottomLayoutOverflow(LayoutUnit lineBottom) const 231 { 232 if (m_overflow) 233 return isHorizontal() ? m_overflow->layoutOverflowRect().maxY() : m_overflow->layoutOverflowRect().maxX(); 234 return lineBottom; 235 } 236 LayoutRect logicalLayoutOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const 237 { 238 LayoutRect result = layoutOverflowRect(lineTop, lineBottom); 239 if (!renderer().isHorizontalWritingMode()) 240 result = result.transposedRect(); 241 return result; 242 } 243 244 LayoutRect visualOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const 245 { 246 return m_overflow ? m_overflow->visualOverflowRect() : enclosingLayoutRect(frameRectIncludingLineHeight(lineTop, lineBottom)); 247 } 248 LayoutUnit logicalLeftVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->visualOverflowRect().x() : m_overflow->visualOverflowRect().y()) : LayoutUnit(logicalLeft()); } 249 LayoutUnit logicalRightVisualOverflow() const { return m_overflow ? (isHorizontal() ? m_overflow->visualOverflowRect().maxX() : m_overflow->visualOverflowRect().maxY()) : LayoutUnit(ceilf(logicalRight())); } 250 LayoutUnit logicalTopVisualOverflow(LayoutUnit lineTop) const 251 { 252 if (m_overflow) 253 return isHorizontal() ? m_overflow->visualOverflowRect().y() : m_overflow->visualOverflowRect().x(); 254 return lineTop; 255 } 256 LayoutUnit logicalBottomVisualOverflow(LayoutUnit lineBottom) const 257 { 258 if (m_overflow) 259 return isHorizontal() ? m_overflow->visualOverflowRect().maxY() : m_overflow->visualOverflowRect().maxX(); 260 return lineBottom; 261 } 262 LayoutRect logicalVisualOverflowRect(LayoutUnit lineTop, LayoutUnit lineBottom) const 263 { 264 LayoutRect result = visualOverflowRect(lineTop, lineBottom); 265 if (!renderer().isHorizontalWritingMode()) 266 result = result.transposedRect(); 267 return result; 268 } 269 270 void setOverflowFromLogicalRects(const LayoutRect& logicalLayoutOverflow, const LayoutRect& logicalVisualOverflow, LayoutUnit lineTop, LayoutUnit lineBottom); 271 void setLayoutOverflow(const LayoutRect&, LayoutUnit lineTop, LayoutUnit lineBottom); 272 void setVisualOverflow(const LayoutRect&, LayoutUnit lineTop, LayoutUnit lineBottom); 273 274 FloatRect frameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const 275 { 276 if (isHorizontal()) 277 return FloatRect(m_topLeft.x(), lineTop, width(), lineBottom - lineTop); 278 return FloatRect(lineTop, m_topLeft.y(), lineBottom - lineTop, height()); 279 } 280 281 FloatRect logicalFrameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const 282 { 283 return FloatRect(logicalLeft(), lineTop, logicalWidth(), lineBottom - lineTop); 284 } 285 286 bool descendantsHaveSameLineHeightAndBaseline() const { return m_descendantsHaveSameLineHeightAndBaseline; } 287 void clearDescendantsHaveSameLineHeightAndBaseline() 288 { 289 m_descendantsHaveSameLineHeightAndBaseline = false; 290 if (parent() && parent()->descendantsHaveSameLineHeightAndBaseline()) 291 parent()->clearDescendantsHaveSameLineHeightAndBaseline(); 292 } 293 294private: 295 virtual bool isInlineFlowBox() const override final { return true; } 296 void boxModelObject() const = delete; 297 298 void addBoxShadowVisualOverflow(LayoutRect& logicalVisualOverflow); 299 void addBorderOutsetVisualOverflow(LayoutRect& logicalVisualOverflow); 300 void addTextBoxVisualOverflow(InlineTextBox&, GlyphOverflowAndFallbackFontsMap&, LayoutRect& logicalVisualOverflow); 301 void addReplacedChildOverflow(const InlineBox*, LayoutRect& logicalLayoutOverflow, LayoutRect& logicalVisualOverflow); 302 void constrainToLineTopAndBottomIfNeeded(LayoutRect&) const; 303 304protected: 305 RefPtr<RenderOverflow> m_overflow; 306 307 InlineBox* m_firstChild; 308 InlineBox* m_lastChild; 309 310 InlineFlowBox* m_prevLineBox; // The previous box that also uses our RenderObject 311 InlineFlowBox* m_nextLineBox; // The next box that also uses our RenderObject 312 313 // Maximum logicalTop among all children of an InlineFlowBox. Used to 314 // calculate the offset for TextUnderlinePositionUnder. 315 void computeMaxLogicalTop(float& maxLogicalTop) const; 316private: 317 unsigned m_includeLogicalLeftEdge : 1; 318 unsigned m_includeLogicalRightEdge : 1; 319 unsigned m_hasTextChildren : 1; 320 unsigned m_hasTextDescendants : 1; 321 unsigned m_descendantsHaveSameLineHeightAndBaseline : 1; 322 323protected: 324 // The following members are only used by RootInlineBox but moved here to keep the bits packed. 325 326 // Whether or not this line uses alphabetic or ideographic baselines by default. 327 unsigned m_baselineType : 1; // FontBaseline 328 329 // If the line contains any ruby runs, then this will be true. 330 unsigned m_hasAnnotationsBefore : 1; 331 unsigned m_hasAnnotationsAfter : 1; 332 333 unsigned m_lineBreakBidiStatusEor : 5; // UCharDirection 334 unsigned m_lineBreakBidiStatusLastStrong : 5; // UCharDirection 335 unsigned m_lineBreakBidiStatusLast : 5; // UCharDirection 336 337 unsigned m_isFirstAfterPageBreak : 1; 338 339 // End of RootInlineBox-specific members. 340 341#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED 342private: 343 unsigned m_hasBadChildList : 1; 344#endif 345}; 346 347INLINE_BOX_OBJECT_TYPE_CASTS(InlineFlowBox, isInlineFlowBox()) 348 349#ifdef NDEBUG 350 351inline void InlineFlowBox::checkConsistency() const 352{ 353} 354 355#endif 356 357#if ASSERT_WITH_SECURITY_IMPLICATION_DISABLED 358 359inline void InlineFlowBox::setHasBadChildList() 360{ 361} 362 363#endif 364 365} // namespace WebCore 366 367#ifndef NDEBUG 368// Outside the WebCore namespace for ease of invocation from gdb. 369void showTree(const WebCore::InlineFlowBox*); 370#endif 371 372#endif // InlineFlowBox_h 373