1/* 2 * Copyright (C) 1997 Martin Jones (mjones@kde.org) 3 * (C) 1997 Torben Weis (weis@kde.org) 4 * (C) 1998 Waldo Bastian (bastian@kde.org) 5 * (C) 1999 Lars Knoll (knoll@kde.org) 6 * (C) 1999 Antti Koivisto (koivisto@kde.org) 7 * Copyright (C) 2003, 2004, 2005, 2006, 2009, 2010, 2014 Apple Inc. All rights reserved. 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Library General Public 11 * License as published by the Free Software Foundation; either 12 * version 2 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Library General Public License for more details. 18 * 19 * You should have received a copy of the GNU Library General Public License 20 * along with this library; see the file COPYING.LIB. If not, write to 21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 * Boston, MA 02110-1301, USA. 23 */ 24 25#ifndef RenderTable_h 26#define RenderTable_h 27 28#include "CSSPropertyNames.h" 29#include "CollapsedBorderValue.h" 30#include "RenderBlock.h" 31#include <memory> 32#include <wtf/HashMap.h> 33#include <wtf/Vector.h> 34 35namespace WebCore { 36 37class RenderTableCol; 38class RenderTableCaption; 39class RenderTableCell; 40class RenderTableSection; 41class TableLayout; 42 43enum SkipEmptySectionsValue { DoNotSkipEmptySections, SkipEmptySections }; 44 45class RenderTable : public RenderBlock { 46public: 47 RenderTable(Element&, PassRef<RenderStyle>); 48 RenderTable(Document&, PassRef<RenderStyle>); 49 virtual ~RenderTable(); 50 51 // Per CSS 3 writing-mode: "The first and second values of the 'border-spacing' property represent spacing between columns 52 // and rows respectively, not necessarily the horizontal and vertical spacing respectively". 53 int hBorderSpacing() const { return m_hSpacing; } 54 int vBorderSpacing() const { return m_vSpacing; } 55 56 bool collapseBorders() const { return style().borderCollapse(); } 57 58 virtual LayoutUnit borderStart() const override { return m_borderStart; } 59 virtual LayoutUnit borderEnd() const override { return m_borderEnd; } 60 virtual LayoutUnit borderBefore() const override; 61 virtual LayoutUnit borderAfter() const override; 62 63 virtual LayoutUnit borderLeft() const override 64 { 65 if (style().isHorizontalWritingMode()) 66 return style().isLeftToRightDirection() ? borderStart() : borderEnd(); 67 return style().isFlippedBlocksWritingMode() ? borderAfter() : borderBefore(); 68 } 69 70 virtual LayoutUnit borderRight() const override 71 { 72 if (style().isHorizontalWritingMode()) 73 return style().isLeftToRightDirection() ? borderEnd() : borderStart(); 74 return style().isFlippedBlocksWritingMode() ? borderBefore() : borderAfter(); 75 } 76 77 virtual LayoutUnit borderTop() const override 78 { 79 if (style().isHorizontalWritingMode()) 80 return style().isFlippedBlocksWritingMode() ? borderAfter() : borderBefore(); 81 return style().isLeftToRightDirection() ? borderStart() : borderEnd(); 82 } 83 84 virtual LayoutUnit borderBottom() const override 85 { 86 if (style().isHorizontalWritingMode()) 87 return style().isFlippedBlocksWritingMode() ? borderBefore() : borderAfter(); 88 return style().isLeftToRightDirection() ? borderEnd() : borderStart(); 89 } 90 91 Color bgColor() const { return style().visitedDependentColor(CSSPropertyBackgroundColor); } 92 93 int outerBorderBefore() const; 94 int outerBorderAfter() const; 95 int outerBorderStart() const; 96 int outerBorderEnd() const; 97 98 int outerBorderLeft() const 99 { 100 if (style().isHorizontalWritingMode()) 101 return style().isLeftToRightDirection() ? outerBorderStart() : outerBorderEnd(); 102 return style().isFlippedBlocksWritingMode() ? outerBorderAfter() : outerBorderBefore(); 103 } 104 105 int outerBorderRight() const 106 { 107 if (style().isHorizontalWritingMode()) 108 return style().isLeftToRightDirection() ? outerBorderEnd() : outerBorderStart(); 109 return style().isFlippedBlocksWritingMode() ? outerBorderBefore() : outerBorderAfter(); 110 } 111 112 int outerBorderTop() const 113 { 114 if (style().isHorizontalWritingMode()) 115 return style().isFlippedBlocksWritingMode() ? outerBorderAfter() : outerBorderBefore(); 116 return style().isLeftToRightDirection() ? outerBorderStart() : outerBorderEnd(); 117 } 118 119 int outerBorderBottom() const 120 { 121 if (style().isHorizontalWritingMode()) 122 return style().isFlippedBlocksWritingMode() ? outerBorderBefore() : outerBorderAfter(); 123 return style().isLeftToRightDirection() ? outerBorderEnd() : outerBorderStart(); 124 } 125 126 int calcBorderStart() const; 127 int calcBorderEnd() const; 128 void recalcBordersInRowDirection(); 129 130 virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) override final; 131 132 struct ColumnStruct { 133 explicit ColumnStruct(unsigned initialSpan = 1) 134 : span(initialSpan) 135 { 136 } 137 138 unsigned span; 139 }; 140 141 void forceSectionsRecalc() 142 { 143 setNeedsSectionRecalc(); 144 recalcSections(); 145 } 146 147 const Vector<ColumnStruct>& columns() const { return m_columns; } 148 const Vector<int>& columnPositions() const { return m_columnPos; } 149 void setColumnPosition(unsigned index, int position) 150 { 151 // Note that if our horizontal border-spacing changed, our position will change but not 152 // our column's width. In practice, horizontal border-spacing won't change often. 153 m_columnLogicalWidthChanged |= m_columnPos[index] != position; 154 m_columnPos[index] = position; 155 } 156 157 RenderTableSection* header() const { return m_head; } 158 RenderTableSection* footer() const { return m_foot; } 159 RenderTableSection* firstBody() const { return m_firstBody; } 160 161 // This function returns 0 if the table has no section. 162 RenderTableSection* topSection() const; 163 RenderTableSection* bottomSection() const; 164 165 // This function returns 0 if the table has no non-empty sections. 166 RenderTableSection* topNonEmptySection() const; 167 168 unsigned lastColumnIndex() const { return numEffCols() - 1; } 169 170 void splitColumn(unsigned position, unsigned firstSpan); 171 void appendColumn(unsigned span); 172 unsigned numEffCols() const { return m_columns.size(); } 173 unsigned spanOfEffCol(unsigned effCol) const { return m_columns[effCol].span; } 174 175 unsigned colToEffCol(unsigned column) const 176 { 177 if (!m_hasCellColspanThatDeterminesTableWidth) 178 return column; 179 180 unsigned effColumn = 0; 181 unsigned numColumns = numEffCols(); 182 for (unsigned c = 0; effColumn < numColumns && c + m_columns[effColumn].span - 1 < column; ++effColumn) 183 c += m_columns[effColumn].span; 184 return effColumn; 185 } 186 187 unsigned effColToCol(unsigned effCol) const 188 { 189 if (!m_hasCellColspanThatDeterminesTableWidth) 190 return effCol; 191 192 unsigned c = 0; 193 for (unsigned i = 0; i < effCol; i++) 194 c += m_columns[i].span; 195 return c; 196 } 197 198 LayoutUnit borderSpacingInRowDirection() const 199 { 200 if (unsigned effectiveColumnCount = numEffCols()) 201 return (effectiveColumnCount + 1) * hBorderSpacing(); 202 203 return 0; 204 } 205 206 // Override paddingStart/End to return pixel values to match behavor of RenderTableCell. 207 virtual LayoutUnit paddingEnd() const override final { return static_cast<int>(RenderBlock::paddingEnd()); } 208 virtual LayoutUnit paddingStart() const override final { return static_cast<int>(RenderBlock::paddingStart()); } 209 210 LayoutUnit bordersPaddingAndSpacingInRowDirection() const 211 { 212 // 'border-spacing' only applies to separate borders (see 17.6.1 The separated borders model). 213 return borderStart() + borderEnd() + (collapseBorders() ? LayoutUnit() : (paddingStart() + paddingEnd() + borderSpacingInRowDirection())); 214 } 215 216 // Return the first column or column-group. 217 RenderTableCol* firstColumn() const; 218 219 RenderTableCol* colElement(unsigned col, bool* startEdge = 0, bool* endEdge = 0) const 220 { 221 // The common case is to not have columns, make that case fast. 222 if (!m_hasColElements) 223 return 0; 224 return slowColElement(col, startEdge, endEdge); 225 } 226 227 bool needsSectionRecalc() const { return m_needsSectionRecalc; } 228 void setNeedsSectionRecalc() 229 { 230 if (documentBeingDestroyed()) 231 return; 232 m_needsSectionRecalc = true; 233 setNeedsLayout(); 234 } 235 236 RenderTableSection* sectionAbove(const RenderTableSection*, SkipEmptySectionsValue = DoNotSkipEmptySections) const; 237 RenderTableSection* sectionBelow(const RenderTableSection*, SkipEmptySectionsValue = DoNotSkipEmptySections) const; 238 239 RenderTableCell* cellAbove(const RenderTableCell*) const; 240 RenderTableCell* cellBelow(const RenderTableCell*) const; 241 RenderTableCell* cellBefore(const RenderTableCell*) const; 242 RenderTableCell* cellAfter(const RenderTableCell*) const; 243 244 typedef Vector<CollapsedBorderValue> CollapsedBorderValues; 245 void invalidateCollapsedBorders() 246 { 247 m_collapsedBordersValid = false; 248 m_collapsedBorders.clear(); 249 } 250 const CollapsedBorderValue* currentBorderValue() const { return m_currentBorder; } 251 252 bool hasSections() const { return m_head || m_foot || m_firstBody; } 253 254 void recalcSectionsIfNeeded() const 255 { 256 if (m_needsSectionRecalc) 257 recalcSections(); 258 } 259 260 static RenderTable* createAnonymousWithParentRenderer(const RenderObject*); 261 virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const override 262 { 263 return createAnonymousWithParentRenderer(parent); 264 } 265 266 const BorderValue& tableStartBorderAdjoiningCell(const RenderTableCell*) const; 267 const BorderValue& tableEndBorderAdjoiningCell(const RenderTableCell*) const; 268 269 void addCaption(const RenderTableCaption*); 270 void removeCaption(const RenderTableCaption*); 271 void addColumn(const RenderTableCol*); 272 void removeColumn(const RenderTableCol*); 273 274 LayoutUnit offsetTopForColumn(const RenderTableCol&) const; 275 LayoutUnit offsetLeftForColumn(const RenderTableCol&) const; 276 LayoutUnit offsetWidthForColumn(const RenderTableCol&) const; 277 LayoutUnit offsetHeightForColumn(const RenderTableCol&) const; 278 279protected: 280 virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override final; 281 virtual void simplifiedNormalFlowLayout() override final; 282 283private: 284 virtual const char* renderName() const override { return "RenderTable"; } 285 286 virtual bool isTable() const override final { return true; } 287 288 virtual bool avoidsFloats() const override final { return true; } 289 290 virtual void paint(PaintInfo&, const LayoutPoint&) override final; 291 virtual void paintObject(PaintInfo&, const LayoutPoint&) override final; 292 virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&) override final; 293 virtual void paintMask(PaintInfo&, const LayoutPoint&) override final; 294 virtual void layout() override final; 295 virtual void computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) const override final; 296 virtual void computePreferredLogicalWidths() override; 297 virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override; 298 299 virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const override final; 300 virtual int firstLineBaseline() const override; 301 virtual int inlineBlockBaseline(LineDirectionMode) const override final; 302 303 RenderTableCol* slowColElement(unsigned col, bool* startEdge, bool* endEdge) const; 304 305 void updateColumnCache() const; 306 void invalidateCachedColumns(); 307 308 void invalidateCachedColumnOffsets(); 309 310 virtual RenderBlock* firstLineBlock() const override final; 311 virtual void updateFirstLetter() override final; 312 313 virtual void updateLogicalWidth() override final; 314 315 LayoutUnit convertStyleLogicalWidthToComputedWidth(const Length& styleLogicalWidth, LayoutUnit availableWidth); 316 LayoutUnit convertStyleLogicalHeightToComputedHeight(const Length& styleLogicalHeight); 317 318 virtual LayoutRect overflowClipRect(const LayoutPoint& location, RenderRegion*, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, PaintPhase = PaintPhaseBlockBackground) override final; 319 virtual LayoutRect overflowClipRectForChildLayers(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy) override { return RenderBox::overflowClipRect(location, region, relevancy); } 320 321 virtual void addOverflowFromChildren() override final; 322 323 void subtractCaptionRect(LayoutRect&) const; 324 325 void recalcCollapsedBorders(); 326 void recalcSections() const; 327 void layoutCaption(RenderTableCaption*); 328 329 void distributeExtraLogicalHeight(int extraLogicalHeight); 330 331 mutable Vector<int> m_columnPos; 332 mutable Vector<ColumnStruct> m_columns; 333 mutable Vector<RenderTableCaption*> m_captions; 334 mutable Vector<RenderTableCol*> m_columnRenderers; 335 336 unsigned effectiveIndexOfColumn(const RenderTableCol&) const; 337 typedef HashMap<const RenderTableCol*, unsigned> EffectiveColumnIndexMap; 338 mutable EffectiveColumnIndexMap m_effectiveColumnIndexMap; 339 340 mutable RenderTableSection* m_head; 341 mutable RenderTableSection* m_foot; 342 mutable RenderTableSection* m_firstBody; 343 344 std::unique_ptr<TableLayout> m_tableLayout; 345 346 CollapsedBorderValues m_collapsedBorders; 347 const CollapsedBorderValue* m_currentBorder; 348 bool m_collapsedBordersValid : 1; 349 350 mutable bool m_hasColElements : 1; 351 mutable bool m_needsSectionRecalc : 1; 352 353 bool m_columnLogicalWidthChanged : 1; 354 mutable bool m_columnRenderersValid: 1; 355 mutable bool m_hasCellColspanThatDeterminesTableWidth : 1; 356 357 bool hasCellColspanThatDeterminesTableWidth() const 358 { 359 for (unsigned c = 0; c < numEffCols(); c++) { 360 if (m_columns[c].span > 1) 361 return true; 362 } 363 return false; 364 } 365 366 short m_hSpacing; 367 short m_vSpacing; 368 int m_borderStart; 369 int m_borderEnd; 370 mutable LayoutUnit m_columnOffsetTop; 371 mutable LayoutUnit m_columnOffsetHeight; 372}; 373 374inline RenderTableSection* RenderTable::topSection() const 375{ 376 ASSERT(!needsSectionRecalc()); 377 if (m_head) 378 return m_head; 379 if (m_firstBody) 380 return m_firstBody; 381 return m_foot; 382} 383 384RENDER_OBJECT_TYPE_CASTS(RenderTable, isTable()) 385 386} // namespace WebCore 387 388#endif // RenderTable_h 389