nsTableCellFrame.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "nsTableCellFrame.h"
  6. #include "gfxUtils.h"
  7. #include "mozilla/gfx/2D.h"
  8. #include "mozilla/gfx/Helpers.h"
  9. #include "nsTableFrame.h"
  10. #include "nsTableColFrame.h"
  11. #include "nsTableRowFrame.h"
  12. #include "nsTableRowGroupFrame.h"
  13. #include "nsStyleContext.h"
  14. #include "nsStyleConsts.h"
  15. #include "nsPresContext.h"
  16. #include "nsRenderingContext.h"
  17. #include "nsCSSRendering.h"
  18. #include "nsIContent.h"
  19. #include "nsGenericHTMLElement.h"
  20. #include "nsAttrValueInlines.h"
  21. #include "nsHTMLParts.h"
  22. #include "nsGkAtoms.h"
  23. #include "nsIPresShell.h"
  24. #include "nsCOMPtr.h"
  25. #include "nsIServiceManager.h"
  26. #include "nsIDOMNode.h"
  27. #include "nsNameSpaceManager.h"
  28. #include "nsDisplayList.h"
  29. #include "nsLayoutUtils.h"
  30. #include "nsTextFrame.h"
  31. #include "FrameLayerBuilder.h"
  32. #include <algorithm>
  33. //TABLECELL SELECTION
  34. #include "nsFrameSelection.h"
  35. #include "mozilla/LookAndFeel.h"
  36. using namespace mozilla;
  37. using namespace mozilla::gfx;
  38. using namespace mozilla::image;
  39. nsTableCellFrame::nsTableCellFrame(nsStyleContext* aContext,
  40. nsTableFrame* aTableFrame)
  41. : nsContainerFrame(aContext)
  42. , mDesiredSize(aTableFrame->GetWritingMode())
  43. {
  44. mColIndex = 0;
  45. mPriorAvailISize = 0;
  46. SetContentEmpty(false);
  47. SetHasPctOverBSize(false);
  48. }
  49. nsTableCellFrame::~nsTableCellFrame()
  50. {
  51. }
  52. NS_IMPL_FRAMEARENA_HELPERS(nsTableCellFrame)
  53. void
  54. nsTableCellFrame::Init(nsIContent* aContent,
  55. nsContainerFrame* aParent,
  56. nsIFrame* aPrevInFlow)
  57. {
  58. // Let the base class do its initialization
  59. nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
  60. if (HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER)) {
  61. AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
  62. }
  63. if (aPrevInFlow) {
  64. // Set the column index
  65. nsTableCellFrame* cellFrame = (nsTableCellFrame*)aPrevInFlow;
  66. uint32_t colIndex = cellFrame->ColIndex();
  67. SetColIndex(colIndex);
  68. }
  69. }
  70. void
  71. nsTableCellFrame::DestroyFrom(nsIFrame* aDestructRoot)
  72. {
  73. if (HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) {
  74. nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot);
  75. }
  76. nsContainerFrame::DestroyFrom(aDestructRoot);
  77. }
  78. // nsIPercentBSizeObserver methods
  79. void
  80. nsTableCellFrame::NotifyPercentBSize(const ReflowInput& aReflowInput)
  81. {
  82. // ReflowInput ensures the mCBReflowInput of blocks inside a
  83. // cell is the cell frame, not the inner-cell block, and that the
  84. // containing block of an inner table is the containing block of its
  85. // table wrapper.
  86. // XXXldb Given the now-stricter |NeedsToObserve|, many if not all of
  87. // these tests are probably unnecessary.
  88. // Maybe the cell reflow state; we sure if we're inside the |if|.
  89. const ReflowInput *cellRI = aReflowInput.mCBReflowInput;
  90. if (cellRI && cellRI->mFrame == this &&
  91. (cellRI->ComputedBSize() == NS_UNCONSTRAINEDSIZE ||
  92. cellRI->ComputedBSize() == 0)) { // XXXldb Why 0?
  93. // This is a percentage bsize on a frame whose percentage bsizes
  94. // are based on the bsize of the cell, since its containing block
  95. // is the inner cell frame.
  96. // We'll only honor the percent bsize if sibling-cells/ancestors
  97. // have specified/pct bsize. (Also, siblings only count for this if
  98. // both this cell and the sibling cell span exactly 1 row.)
  99. if (nsTableFrame::AncestorsHaveStyleBSize(*cellRI) ||
  100. (GetTableFrame()->GetEffectiveRowSpan(*this) == 1 &&
  101. cellRI->mParentReflowInput->mFrame->
  102. HasAnyStateBits(NS_ROW_HAS_CELL_WITH_STYLE_BSIZE))) {
  103. for (const ReflowInput *rs = aReflowInput.mParentReflowInput;
  104. rs != cellRI;
  105. rs = rs->mParentReflowInput) {
  106. rs->mFrame->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
  107. }
  108. nsTableFrame::RequestSpecialBSizeReflow(*cellRI);
  109. }
  110. }
  111. }
  112. // The cell needs to observe its block and things inside its block but nothing below that
  113. bool
  114. nsTableCellFrame::NeedsToObserve(const ReflowInput& aReflowInput)
  115. {
  116. const ReflowInput *rs = aReflowInput.mParentReflowInput;
  117. if (!rs)
  118. return false;
  119. if (rs->mFrame == this) {
  120. // We always observe the child block. It will never send any
  121. // notifications, but we need this so that the observer gets
  122. // propagated to its kids.
  123. return true;
  124. }
  125. rs = rs->mParentReflowInput;
  126. if (!rs) {
  127. return false;
  128. }
  129. // We always need to let the percent bsize observer be propagated
  130. // from a table wrapper frame to an inner table frame.
  131. nsIAtom *fType = aReflowInput.mFrame->GetType();
  132. if (fType == nsGkAtoms::tableFrame) {
  133. return true;
  134. }
  135. // We need the observer to be propagated to all children of the cell
  136. // (i.e., children of the child block) in quirks mode, but only to
  137. // tables in standards mode.
  138. // XXX This may not be true in the case of orthogonal flows within
  139. // the cell (bug 1174711 comment 8); we may need to observe isizes
  140. // instead of bsizes for orthogonal children.
  141. return rs->mFrame == this &&
  142. (PresContext()->CompatibilityMode() == eCompatibility_NavQuirks ||
  143. fType == nsGkAtoms::tableWrapperFrame);
  144. }
  145. nsresult
  146. nsTableCellFrame::AttributeChanged(int32_t aNameSpaceID,
  147. nsIAtom* aAttribute,
  148. int32_t aModType)
  149. {
  150. // We need to recalculate in this case because of the nowrap quirk in
  151. // BasicTableLayoutStrategy
  152. if (aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::nowrap &&
  153. PresContext()->CompatibilityMode() == eCompatibility_NavQuirks) {
  154. PresContext()->PresShell()->
  155. FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
  156. }
  157. // let the table frame decide what to do
  158. GetTableFrame()->AttributeChangedFor(this, mContent, aAttribute);
  159. return NS_OK;
  160. }
  161. /* virtual */ void
  162. nsTableCellFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
  163. {
  164. nsContainerFrame::DidSetStyleContext(aOldStyleContext);
  165. if (!aOldStyleContext) //avoid this on init
  166. return;
  167. nsTableFrame* tableFrame = GetTableFrame();
  168. if (tableFrame->IsBorderCollapse() &&
  169. tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) {
  170. uint32_t colIndex = ColIndex();
  171. uint32_t rowIndex = RowIndex();
  172. // row span needs to be clamped as we do not create rows in the cellmap
  173. // which do not have cells originating in them
  174. TableArea damageArea(colIndex, rowIndex, GetColSpan(),
  175. std::min(static_cast<uint32_t>(GetRowSpan()),
  176. tableFrame->GetRowCount() - rowIndex));
  177. tableFrame->AddBCDamageArea(damageArea);
  178. }
  179. }
  180. #ifdef DEBUG
  181. void
  182. nsTableCellFrame::AppendFrames(ChildListID aListID,
  183. nsFrameList& aFrameList)
  184. {
  185. MOZ_CRASH("unsupported operation");
  186. }
  187. void
  188. nsTableCellFrame::InsertFrames(ChildListID aListID,
  189. nsIFrame* aPrevFrame,
  190. nsFrameList& aFrameList)
  191. {
  192. MOZ_CRASH("unsupported operation");
  193. }
  194. void
  195. nsTableCellFrame::RemoveFrame(ChildListID aListID,
  196. nsIFrame* aOldFrame)
  197. {
  198. MOZ_CRASH("unsupported operation");
  199. }
  200. #endif
  201. void nsTableCellFrame::SetColIndex(int32_t aColIndex)
  202. {
  203. mColIndex = aColIndex;
  204. }
  205. /* virtual */ nsMargin
  206. nsTableCellFrame::GetUsedMargin() const
  207. {
  208. return nsMargin(0,0,0,0);
  209. }
  210. //ASSURE DIFFERENT COLORS for selection
  211. inline nscolor EnsureDifferentColors(nscolor colorA, nscolor colorB)
  212. {
  213. if (colorA == colorB)
  214. {
  215. nscolor res;
  216. res = NS_RGB(NS_GET_R(colorA) ^ 0xff,
  217. NS_GET_G(colorA) ^ 0xff,
  218. NS_GET_B(colorA) ^ 0xff);
  219. return res;
  220. }
  221. return colorA;
  222. }
  223. void
  224. nsTableCellFrame::DecorateForSelection(DrawTarget* aDrawTarget, nsPoint aPt)
  225. {
  226. NS_ASSERTION(IsSelected(), "Should only be called for selected cells");
  227. int16_t displaySelection;
  228. nsPresContext* presContext = PresContext();
  229. displaySelection = DisplaySelection(presContext);
  230. if (displaySelection) {
  231. RefPtr<nsFrameSelection> frameSelection =
  232. presContext->PresShell()->FrameSelection();
  233. if (frameSelection->GetTableCellSelection()) {
  234. nscolor bordercolor;
  235. if (displaySelection == nsISelectionController::SELECTION_DISABLED) {
  236. bordercolor = NS_RGB(176,176,176);// disabled color
  237. }
  238. else {
  239. bordercolor =
  240. LookAndFeel::GetColor(LookAndFeel::eColorID_TextSelectBackground);
  241. }
  242. nscoord threePx = nsPresContext::CSSPixelsToAppUnits(3);
  243. if ((mRect.width > threePx) && (mRect.height > threePx))
  244. {
  245. //compare bordercolor to ((nsStyleColor *)myColor)->mBackgroundColor)
  246. bordercolor = EnsureDifferentColors(bordercolor,
  247. StyleBackground()->mBackgroundColor);
  248. int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
  249. Point devPixelOffset = NSPointToPoint(aPt, appUnitsPerDevPixel);
  250. AutoRestoreTransform autoRestoreTransform(aDrawTarget);
  251. aDrawTarget->SetTransform(
  252. aDrawTarget->GetTransform().PreTranslate(devPixelOffset));
  253. ColorPattern color(ToDeviceColor(bordercolor));
  254. nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
  255. StrokeLineWithSnapping(nsPoint(onePixel, 0), nsPoint(mRect.width, 0),
  256. appUnitsPerDevPixel, *aDrawTarget, color);
  257. StrokeLineWithSnapping(nsPoint(0, onePixel), nsPoint(0, mRect.height),
  258. appUnitsPerDevPixel, *aDrawTarget, color);
  259. StrokeLineWithSnapping(nsPoint(onePixel, mRect.height),
  260. nsPoint(mRect.width, mRect.height),
  261. appUnitsPerDevPixel, *aDrawTarget, color);
  262. StrokeLineWithSnapping(nsPoint(mRect.width, onePixel),
  263. nsPoint(mRect.width, mRect.height),
  264. appUnitsPerDevPixel, *aDrawTarget, color);
  265. //middle
  266. nsRect r(onePixel, onePixel,
  267. mRect.width - onePixel, mRect.height - onePixel);
  268. Rect devPixelRect =
  269. NSRectToSnappedRect(r, appUnitsPerDevPixel, *aDrawTarget);
  270. aDrawTarget->StrokeRect(devPixelRect, color);
  271. //shading
  272. StrokeLineWithSnapping(nsPoint(2*onePixel, mRect.height-2*onePixel),
  273. nsPoint(mRect.width-onePixel, mRect.height- (2*onePixel)),
  274. appUnitsPerDevPixel, *aDrawTarget, color);
  275. StrokeLineWithSnapping(nsPoint(mRect.width - (2*onePixel), 2*onePixel),
  276. nsPoint(mRect.width - (2*onePixel), mRect.height-onePixel),
  277. appUnitsPerDevPixel, *aDrawTarget, color);
  278. }
  279. }
  280. }
  281. }
  282. DrawResult
  283. nsTableCellFrame::PaintBackground(nsRenderingContext& aRenderingContext,
  284. const nsRect& aDirtyRect,
  285. nsPoint aPt,
  286. uint32_t aFlags)
  287. {
  288. nsRect rect(aPt, GetSize());
  289. nsCSSRendering::PaintBGParams params =
  290. nsCSSRendering::PaintBGParams::ForAllLayers(*PresContext(),
  291. aRenderingContext,
  292. aDirtyRect, rect,
  293. this, aFlags);
  294. return nsCSSRendering::PaintBackground(params);
  295. }
  296. nsresult
  297. nsTableCellFrame::ProcessBorders(nsTableFrame* aFrame,
  298. nsDisplayListBuilder* aBuilder,
  299. const nsDisplayListSet& aLists)
  300. {
  301. const nsStyleBorder* borderStyle = StyleBorder();
  302. if (aFrame->IsBorderCollapse() || !borderStyle->HasBorder())
  303. return NS_OK;
  304. if (!GetContentEmpty() ||
  305. StyleTableBorder()->mEmptyCells == NS_STYLE_TABLE_EMPTY_CELLS_SHOW) {
  306. aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
  307. nsDisplayBorder(aBuilder, this));
  308. }
  309. return NS_OK;
  310. }
  311. class nsDisplayTableCellBackground : public nsDisplayTableItem {
  312. public:
  313. nsDisplayTableCellBackground(nsDisplayListBuilder* aBuilder,
  314. nsTableCellFrame* aFrame) :
  315. nsDisplayTableItem(aBuilder, aFrame) {
  316. MOZ_COUNT_CTOR(nsDisplayTableCellBackground);
  317. }
  318. #ifdef NS_BUILD_REFCNT_LOGGING
  319. virtual ~nsDisplayTableCellBackground() {
  320. MOZ_COUNT_DTOR(nsDisplayTableCellBackground);
  321. }
  322. #endif
  323. virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
  324. HitTestState* aState,
  325. nsTArray<nsIFrame*> *aOutFrames) override {
  326. aOutFrames->AppendElement(mFrame);
  327. }
  328. virtual void Paint(nsDisplayListBuilder* aBuilder,
  329. nsRenderingContext* aCtx) override;
  330. virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
  331. bool* aSnap) override;
  332. NS_DISPLAY_DECL_NAME("TableCellBackground", TYPE_TABLE_CELL_BACKGROUND)
  333. };
  334. void nsDisplayTableCellBackground::Paint(nsDisplayListBuilder* aBuilder,
  335. nsRenderingContext* aCtx)
  336. {
  337. DrawResult result = static_cast<nsTableCellFrame*>(mFrame)->
  338. PaintBackground(*aCtx, mVisibleRect, ToReferenceFrame(),
  339. aBuilder->GetBackgroundPaintFlags());
  340. nsDisplayTableItemGeometry::UpdateDrawResult(this, result);
  341. }
  342. nsRect
  343. nsDisplayTableCellBackground::GetBounds(nsDisplayListBuilder* aBuilder,
  344. bool* aSnap)
  345. {
  346. // revert from nsDisplayTableItem's implementation ... cell backgrounds
  347. // don't overflow the cell
  348. return nsDisplayItem::GetBounds(aBuilder, aSnap);
  349. }
  350. void nsTableCellFrame::InvalidateFrame(uint32_t aDisplayItemKey)
  351. {
  352. nsIFrame::InvalidateFrame(aDisplayItemKey);
  353. GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
  354. }
  355. void nsTableCellFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
  356. {
  357. nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
  358. // If we have filters applied that would affects our bounds, then
  359. // we get an inactive layer created and this is computed
  360. // within FrameLayerBuilder
  361. GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
  362. }
  363. static void
  364. PaintTableCellSelection(nsIFrame* aFrame, DrawTarget* aDrawTarget,
  365. const nsRect& aRect, nsPoint aPt)
  366. {
  367. static_cast<nsTableCellFrame*>(aFrame)->DecorateForSelection(aDrawTarget,
  368. aPt);
  369. }
  370. bool
  371. nsTableCellFrame::ShouldPaintBordersAndBackgrounds() const
  372. {
  373. // If we're not visible, we don't paint.
  374. if (!StyleVisibility()->IsVisible()) {
  375. return false;
  376. }
  377. // Consider 'empty-cells', but only in separated borders mode.
  378. if (!GetContentEmpty()) {
  379. return true;
  380. }
  381. nsTableFrame* tableFrame = GetTableFrame();
  382. if (tableFrame->IsBorderCollapse()) {
  383. return true;
  384. }
  385. return StyleTableBorder()->mEmptyCells == NS_STYLE_TABLE_EMPTY_CELLS_SHOW;
  386. }
  387. bool
  388. nsTableCellFrame::ShouldPaintBackground(nsDisplayListBuilder* aBuilder)
  389. {
  390. return ShouldPaintBordersAndBackgrounds() && IsVisibleInSelection(aBuilder);
  391. }
  392. void
  393. nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
  394. const nsDisplayListSet& aLists)
  395. {
  396. DO_GLOBAL_REFLOW_COUNT_DSP("nsTableCellFrame");
  397. if (ShouldPaintBordersAndBackgrounds()) {
  398. // display outset box-shadows if we need to.
  399. bool hasBoxShadow = !!StyleEffects()->mBoxShadow;
  400. if (hasBoxShadow) {
  401. aLists.BorderBackground()->AppendNewToTop(
  402. new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, this));
  403. }
  404. nsRect bgRect = GetRectRelativeToSelf() + aBuilder->ToReferenceFrame(this);
  405. // display background if we need to.
  406. if (aBuilder->IsForEventDelivery() ||
  407. !StyleBackground()->IsTransparent() ||
  408. StyleDisplay()->mAppearance) {
  409. nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
  410. aBuilder, this, bgRect, aLists.BorderBackground());
  411. }
  412. // display inset box-shadows if we need to.
  413. if (hasBoxShadow) {
  414. aLists.BorderBackground()->AppendNewToTop(
  415. new (aBuilder) nsDisplayBoxShadowInner(aBuilder, this));
  416. }
  417. // display borders if we need to
  418. ProcessBorders(GetTableFrame(), aBuilder, aLists);
  419. // and display the selection border if we need to
  420. if (IsSelected()) {
  421. aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
  422. nsDisplayGeneric(aBuilder, this, ::PaintTableCellSelection,
  423. "TableCellSelection",
  424. nsDisplayItem::TYPE_TABLE_CELL_SELECTION));
  425. }
  426. // This can be null if display list building initiated in the middle
  427. // of the table, which can happen with background-clip:text and
  428. // -moz-element.
  429. nsDisplayTableBackgroundSet* backgrounds =
  430. aBuilder->GetTableBackgroundSet();
  431. if (backgrounds) {
  432. // Compute bgRect relative to reference frame, but using the
  433. // normal (without position:relative offsets) positions for the
  434. // cell, row and row group.
  435. bgRect = GetRectRelativeToSelf() + GetNormalPosition();
  436. nsTableRowFrame* row = GetTableRowFrame();
  437. bgRect += row->GetNormalPosition();
  438. nsTableRowGroupFrame* rowGroup = row->GetTableRowGroupFrame();
  439. bgRect += rowGroup->GetNormalPosition();
  440. bgRect += backgrounds->TableToReferenceFrame();
  441. // Create backgrounds items as needed for the column and column
  442. // group that this cell occupies.
  443. nsTableColFrame* col = backgrounds->GetColForIndex(ColIndex());
  444. nsTableColGroupFrame* colGroup = col->GetTableColGroupFrame();
  445. Maybe<nsDisplayListBuilder::AutoBuildingDisplayList> buildingForColGroup;
  446. nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
  447. aBuilder, colGroup, bgRect, backgrounds->ColGroupBackgrounds(), false,
  448. nullptr, colGroup->GetRect() + backgrounds->TableToReferenceFrame(),
  449. this, &buildingForColGroup);
  450. Maybe<nsDisplayListBuilder::AutoBuildingDisplayList> buildingForCol;
  451. nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
  452. aBuilder, col, bgRect, backgrounds->ColBackgrounds(), false, nullptr,
  453. col->GetRect() + colGroup->GetPosition() +
  454. backgrounds->TableToReferenceFrame(),
  455. this, &buildingForCol);
  456. }
  457. }
  458. // the 'empty-cells' property has no effect on 'outline'
  459. DisplayOutline(aBuilder, aLists);
  460. nsIFrame* kid = mFrames.FirstChild();
  461. NS_ASSERTION(kid && !kid->GetNextSibling(), "Table cells should have just one child");
  462. // The child's background will go in our BorderBackground() list.
  463. // This isn't a problem since it won't have a real background except for
  464. // event handling. We do not call BuildDisplayListForNonBlockChildren
  465. // because that/ would put the child's background in the Content() list
  466. // which isn't right (e.g., would end up on top of our child floats for
  467. // event handling).
  468. BuildDisplayListForChild(aBuilder, kid, aLists);
  469. }
  470. nsIFrame::LogicalSides
  471. nsTableCellFrame::GetLogicalSkipSides(const ReflowInput* aReflowInput) const
  472. {
  473. if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
  474. StyleBoxDecorationBreak::Clone)) {
  475. return LogicalSides();
  476. }
  477. LogicalSides skip;
  478. if (nullptr != GetPrevInFlow()) {
  479. skip |= eLogicalSideBitsBStart;
  480. }
  481. if (nullptr != GetNextInFlow()) {
  482. skip |= eLogicalSideBitsBEnd;
  483. }
  484. return skip;
  485. }
  486. /* virtual */ nsMargin
  487. nsTableCellFrame::GetBorderOverflow()
  488. {
  489. return nsMargin(0, 0, 0, 0);
  490. }
  491. // Align the cell's child frame within the cell
  492. void nsTableCellFrame::BlockDirAlignChild(WritingMode aWM, nscoord aMaxAscent)
  493. {
  494. /* It's the 'border-collapse' on the table that matters */
  495. LogicalMargin borderPadding = GetLogicalUsedBorderAndPadding(aWM);
  496. nscoord bStartInset = borderPadding.BStart(aWM);
  497. nscoord bEndInset = borderPadding.BEnd(aWM);
  498. uint8_t verticalAlignFlags = GetVerticalAlign();
  499. nscoord bSize = BSize(aWM);
  500. nsIFrame* firstKid = mFrames.FirstChild();
  501. nsSize containerSize = mRect.Size();
  502. NS_ASSERTION(firstKid, "Frame construction error, a table cell always has "
  503. "an inner cell frame");
  504. LogicalRect kidRect = firstKid->GetLogicalRect(aWM, containerSize);
  505. nscoord childBSize = kidRect.BSize(aWM);
  506. // Vertically align the child
  507. nscoord kidBStart = 0;
  508. switch (verticalAlignFlags)
  509. {
  510. case NS_STYLE_VERTICAL_ALIGN_BASELINE:
  511. // Align the baselines of the child frame with the baselines of
  512. // other children in the same row which have 'vertical-align: baseline'
  513. kidBStart = bStartInset + aMaxAscent - GetCellBaseline();
  514. break;
  515. case NS_STYLE_VERTICAL_ALIGN_TOP:
  516. // Align the top of the child frame with the top of the content area,
  517. kidBStart = bStartInset;
  518. break;
  519. case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
  520. // Align the bottom of the child frame with the bottom of the content area,
  521. kidBStart = bSize - childBSize - bEndInset;
  522. break;
  523. default:
  524. case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
  525. // Align the middle of the child frame with the middle of the content area,
  526. kidBStart = (bSize - childBSize - bEndInset + bStartInset) / 2;
  527. }
  528. // If the content is larger than the cell bsize, align from bStartInset
  529. // (cell's content-box bstart edge).
  530. kidBStart = std::max(bStartInset, kidBStart);
  531. if (kidBStart != kidRect.BStart(aWM)) {
  532. // Invalidate at the old position first
  533. firstKid->InvalidateFrameSubtree();
  534. }
  535. firstKid->SetPosition(aWM, LogicalPoint(aWM, kidRect.IStart(aWM),
  536. kidBStart), containerSize);
  537. ReflowOutput desiredSize(aWM);
  538. desiredSize.SetSize(aWM, GetLogicalSize(aWM));
  539. nsRect overflow(nsPoint(0,0), GetSize());
  540. overflow.Inflate(GetBorderOverflow());
  541. desiredSize.mOverflowAreas.SetAllTo(overflow);
  542. ConsiderChildOverflow(desiredSize.mOverflowAreas, firstKid);
  543. FinishAndStoreOverflow(&desiredSize);
  544. if (kidBStart != kidRect.BStart(aWM)) {
  545. // Make sure any child views are correctly positioned. We know the inner table
  546. // cell won't have a view
  547. nsContainerFrame::PositionChildViews(firstKid);
  548. // Invalidate new overflow rect
  549. firstKid->InvalidateFrameSubtree();
  550. }
  551. if (HasView()) {
  552. nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this,
  553. GetView(),
  554. desiredSize.VisualOverflow(), 0);
  555. }
  556. }
  557. bool
  558. nsTableCellFrame::ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas)
  559. {
  560. nsRect bounds(nsPoint(0,0), GetSize());
  561. bounds.Inflate(GetBorderOverflow());
  562. aOverflowAreas.UnionAllWith(bounds);
  563. return nsContainerFrame::ComputeCustomOverflow(aOverflowAreas);
  564. }
  565. // Per CSS 2.1, we map 'sub', 'super', 'text-top', 'text-bottom',
  566. // length, percentage, and calc() values to 'baseline'.
  567. uint8_t
  568. nsTableCellFrame::GetVerticalAlign() const
  569. {
  570. const nsStyleCoord& verticalAlign = StyleDisplay()->mVerticalAlign;
  571. if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) {
  572. uint8_t value = verticalAlign.GetIntValue();
  573. if (value == NS_STYLE_VERTICAL_ALIGN_TOP ||
  574. value == NS_STYLE_VERTICAL_ALIGN_MIDDLE ||
  575. value == NS_STYLE_VERTICAL_ALIGN_BOTTOM) {
  576. return value;
  577. }
  578. }
  579. return NS_STYLE_VERTICAL_ALIGN_BASELINE;
  580. }
  581. bool
  582. nsTableCellFrame::CellHasVisibleContent(nscoord height,
  583. nsTableFrame* tableFrame,
  584. nsIFrame* kidFrame)
  585. {
  586. // see http://www.w3.org/TR/CSS21/tables.html#empty-cells
  587. if (height > 0)
  588. return true;
  589. if (tableFrame->IsBorderCollapse())
  590. return true;
  591. for (nsIFrame* innerFrame : kidFrame->PrincipalChildList()) {
  592. nsIAtom* frameType = innerFrame->GetType();
  593. if (nsGkAtoms::textFrame == frameType) {
  594. nsTextFrame* textFrame = static_cast<nsTextFrame*>(innerFrame);
  595. if (textFrame->HasNoncollapsedCharacters())
  596. return true;
  597. }
  598. else if (nsGkAtoms::placeholderFrame != frameType) {
  599. return true;
  600. }
  601. else {
  602. nsIFrame *floatFrame = nsLayoutUtils::GetFloatFromPlaceholder(innerFrame);
  603. if (floatFrame)
  604. return true;
  605. }
  606. }
  607. return false;
  608. }
  609. nscoord
  610. nsTableCellFrame::GetCellBaseline() const
  611. {
  612. // Ignore the position of the inner frame relative to the cell frame
  613. // since we want the position as though the inner were top-aligned.
  614. nsIFrame *inner = mFrames.FirstChild();
  615. nscoord borderPadding = GetUsedBorderAndPadding().top;
  616. nscoord result;
  617. if (nsLayoutUtils::GetFirstLineBaseline(GetWritingMode(), inner, &result))
  618. return result + borderPadding;
  619. return inner->GetContentRectRelativeToSelf().YMost() +
  620. borderPadding;
  621. }
  622. int32_t
  623. nsTableCellFrame::GetRowSpan()
  624. {
  625. int32_t rowSpan=1;
  626. // Don't look at the content's rowspan if we're a pseudo cell
  627. if (!StyleContext()->GetPseudo()) {
  628. dom::Element* elem = mContent->AsElement();
  629. const nsAttrValue* attr = elem->GetParsedAttr(nsGkAtoms::rowspan);
  630. // Note that we don't need to check the tag name, because only table cells
  631. // (including MathML <mtd>) and table headers parse the "rowspan" attribute
  632. // into an integer.
  633. if (attr && attr->Type() == nsAttrValue::eInteger) {
  634. rowSpan = attr->GetIntegerValue();
  635. }
  636. }
  637. return rowSpan;
  638. }
  639. int32_t
  640. nsTableCellFrame::GetColSpan()
  641. {
  642. int32_t colSpan=1;
  643. // Don't look at the content's colspan if we're a pseudo cell
  644. if (!StyleContext()->GetPseudo()) {
  645. dom::Element* elem = mContent->AsElement();
  646. const nsAttrValue* attr = elem->GetParsedAttr(
  647. MOZ_UNLIKELY(elem->IsMathMLElement()) ? nsGkAtoms::columnspan_
  648. : nsGkAtoms::colspan);
  649. // Note that we don't need to check the tag name, because only table cells
  650. // (including MathML <mtd>) and table headers parse the "colspan" attribute
  651. // into an integer.
  652. if (attr && attr->Type() == nsAttrValue::eInteger) {
  653. colSpan = attr->GetIntegerValue();
  654. }
  655. }
  656. return colSpan;
  657. }
  658. /* virtual */ nscoord
  659. nsTableCellFrame::GetMinISize(nsRenderingContext *aRenderingContext)
  660. {
  661. nscoord result = 0;
  662. DISPLAY_MIN_WIDTH(this, result);
  663. nsIFrame *inner = mFrames.FirstChild();
  664. result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner,
  665. nsLayoutUtils::MIN_ISIZE);
  666. return result;
  667. }
  668. /* virtual */ nscoord
  669. nsTableCellFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
  670. {
  671. nscoord result = 0;
  672. DISPLAY_PREF_WIDTH(this, result);
  673. nsIFrame *inner = mFrames.FirstChild();
  674. result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner,
  675. nsLayoutUtils::PREF_ISIZE);
  676. return result;
  677. }
  678. /* virtual */ nsIFrame::IntrinsicISizeOffsetData
  679. nsTableCellFrame::IntrinsicISizeOffsets(nscoord aPercentageBasis)
  680. {
  681. IntrinsicISizeOffsetData result =
  682. nsContainerFrame::IntrinsicISizeOffsets(aPercentageBasis);
  683. result.hMargin = 0;
  684. WritingMode wm = GetWritingMode();
  685. result.hBorder = GetBorderWidth(wm).IStartEnd(wm);
  686. return result;
  687. }
  688. #ifdef DEBUG
  689. #define PROBABLY_TOO_LARGE 1000000
  690. static
  691. void DebugCheckChildSize(nsIFrame* aChild,
  692. ReflowOutput& aMet)
  693. {
  694. WritingMode wm = aMet.GetWritingMode();
  695. if ((aMet.ISize(wm) < 0) || (aMet.ISize(wm) > PROBABLY_TOO_LARGE)) {
  696. printf("WARNING: cell content %p has large inline size %d \n",
  697. static_cast<void*>(aChild), int32_t(aMet.ISize(wm)));
  698. }
  699. }
  700. #endif
  701. // the computed bsize for the cell, which descendants use for percent bsize calculations
  702. // it is the bsize (minus border, padding) of the cell's first in flow during its final
  703. // reflow without an unconstrained bsize.
  704. static nscoord
  705. CalcUnpaginatedBSize(nsTableCellFrame& aCellFrame,
  706. nsTableFrame& aTableFrame,
  707. nscoord aBlockDirBorderPadding)
  708. {
  709. const nsTableCellFrame* firstCellInFlow =
  710. static_cast<nsTableCellFrame*>(aCellFrame.FirstInFlow());
  711. nsTableFrame* firstTableInFlow =
  712. static_cast<nsTableFrame*>(aTableFrame.FirstInFlow());
  713. nsTableRowFrame* row =
  714. static_cast<nsTableRowFrame*>(firstCellInFlow->GetParent());
  715. nsTableRowGroupFrame* firstRGInFlow =
  716. static_cast<nsTableRowGroupFrame*>(row->GetParent());
  717. uint32_t rowIndex = firstCellInFlow->RowIndex();
  718. int32_t rowSpan = aTableFrame.GetEffectiveRowSpan(*firstCellInFlow);
  719. nscoord computedBSize = firstTableInFlow->GetRowSpacing(rowIndex,
  720. rowIndex + rowSpan - 1);
  721. computedBSize -= aBlockDirBorderPadding;
  722. uint32_t rowX;
  723. for (row = firstRGInFlow->GetFirstRow(), rowX = 0; row; row = row->GetNextRow(), rowX++) {
  724. if (rowX > rowIndex + rowSpan - 1) {
  725. break;
  726. }
  727. else if (rowX >= rowIndex) {
  728. computedBSize += row->GetUnpaginatedBSize();
  729. }
  730. }
  731. return computedBSize;
  732. }
  733. void
  734. nsTableCellFrame::Reflow(nsPresContext* aPresContext,
  735. ReflowOutput& aDesiredSize,
  736. const ReflowInput& aReflowInput,
  737. nsReflowStatus& aStatus)
  738. {
  739. MarkInReflow();
  740. DO_GLOBAL_REFLOW_COUNT("nsTableCellFrame");
  741. DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
  742. if (aReflowInput.mFlags.mSpecialBSizeReflow) {
  743. FirstInFlow()->AddStateBits(NS_TABLE_CELL_HAD_SPECIAL_REFLOW);
  744. }
  745. // see if a special bsize reflow needs to occur due to having a pct height
  746. nsTableFrame::CheckRequestSpecialBSizeReflow(aReflowInput);
  747. aStatus = NS_FRAME_COMPLETE;
  748. WritingMode wm = aReflowInput.GetWritingMode();
  749. LogicalSize availSize(wm, aReflowInput.AvailableISize(),
  750. aReflowInput.AvailableBSize());
  751. LogicalMargin borderPadding = aReflowInput.ComputedLogicalPadding();
  752. LogicalMargin border = GetBorderWidth(wm);
  753. borderPadding += border;
  754. // reduce available space by insets, if we're in a constrained situation
  755. availSize.ISize(wm) -= borderPadding.IStartEnd(wm);
  756. if (NS_UNCONSTRAINEDSIZE != availSize.BSize(wm)) {
  757. availSize.BSize(wm) -= borderPadding.BStartEnd(wm);
  758. }
  759. // Try to reflow the child into the available space. It might not
  760. // fit or might need continuing.
  761. if (availSize.BSize(wm) < 0) {
  762. availSize.BSize(wm) = 1;
  763. }
  764. ReflowOutput kidSize(wm, aDesiredSize.mFlags);
  765. kidSize.ClearSize();
  766. SetPriorAvailISize(aReflowInput.AvailableISize());
  767. nsIFrame* firstKid = mFrames.FirstChild();
  768. NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame");
  769. nsTableFrame* tableFrame = GetTableFrame();
  770. if (aReflowInput.mFlags.mSpecialBSizeReflow) {
  771. const_cast<ReflowInput&>(aReflowInput).
  772. SetComputedBSize(BSize(wm) - borderPadding.BStartEnd(wm));
  773. DISPLAY_REFLOW_CHANGE();
  774. }
  775. else if (aPresContext->IsPaginated()) {
  776. nscoord computedUnpaginatedBSize =
  777. CalcUnpaginatedBSize((nsTableCellFrame&)*this,
  778. *tableFrame, borderPadding.BStartEnd(wm));
  779. if (computedUnpaginatedBSize > 0) {
  780. const_cast<ReflowInput&>(aReflowInput).SetComputedBSize(computedUnpaginatedBSize);
  781. DISPLAY_REFLOW_CHANGE();
  782. }
  783. }
  784. else {
  785. SetHasPctOverBSize(false);
  786. }
  787. WritingMode kidWM = firstKid->GetWritingMode();
  788. ReflowInput kidReflowInput(aPresContext, aReflowInput, firstKid,
  789. availSize.ConvertTo(kidWM, wm));
  790. // Don't be a percent height observer if we're in the middle of
  791. // special-bsize reflow, in case we get an accidental NotifyPercentBSize()
  792. // call (which we shouldn't honor during special-bsize reflow)
  793. if (!aReflowInput.mFlags.mSpecialBSizeReflow) {
  794. // mPercentBSizeObserver is for children of cells in quirks mode,
  795. // but only those than are tables in standards mode. NeedsToObserve
  796. // will determine how far this is propagated to descendants.
  797. kidReflowInput.mPercentBSizeObserver = this;
  798. }
  799. // Don't propagate special bsize reflow state to our kids
  800. kidReflowInput.mFlags.mSpecialBSizeReflow = false;
  801. if (aReflowInput.mFlags.mSpecialBSizeReflow ||
  802. FirstInFlow()->HasAnyStateBits(NS_TABLE_CELL_HAD_SPECIAL_REFLOW)) {
  803. // We need to force the kid to have mBResize set if we've had a
  804. // special reflow in the past, since the non-special reflow needs to
  805. // resize back to what it was without the special bsize reflow.
  806. kidReflowInput.SetBResize(true);
  807. }
  808. nsSize containerSize =
  809. aReflowInput.ComputedSizeAsContainerIfConstrained();
  810. LogicalPoint kidOrigin(wm, borderPadding.IStart(wm),
  811. borderPadding.BStart(wm));
  812. nsRect origRect = firstKid->GetRect();
  813. nsRect origVisualOverflow = firstKid->GetVisualOverflowRect();
  814. bool firstReflow = firstKid->HasAnyStateBits(NS_FRAME_FIRST_REFLOW);
  815. ReflowChild(firstKid, aPresContext, kidSize, kidReflowInput,
  816. wm, kidOrigin, containerSize, 0, aStatus);
  817. if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
  818. // Don't pass OVERFLOW_INCOMPLETE through tables until they can actually handle it
  819. //XXX should paginate overflow as overflow, but not in this patch (bug 379349)
  820. NS_FRAME_SET_INCOMPLETE(aStatus);
  821. printf("Set table cell incomplete %p\n", static_cast<void*>(this));
  822. }
  823. // XXXbz is this invalidate actually needed, really?
  824. if (HasAnyStateBits(NS_FRAME_IS_DIRTY)) {
  825. InvalidateFrameSubtree();
  826. }
  827. #ifdef DEBUG
  828. DebugCheckChildSize(firstKid, kidSize);
  829. #endif
  830. // 0 dimensioned cells need to be treated specially in Standard/NavQuirks mode
  831. // see testcase "emptyCells.html"
  832. nsIFrame* prevInFlow = GetPrevInFlow();
  833. bool isEmpty;
  834. if (prevInFlow) {
  835. isEmpty = static_cast<nsTableCellFrame*>(prevInFlow)->GetContentEmpty();
  836. } else {
  837. isEmpty = !CellHasVisibleContent(kidSize.Height(), tableFrame, firstKid);
  838. }
  839. SetContentEmpty(isEmpty);
  840. // Place the child
  841. FinishReflowChild(firstKid, aPresContext, kidSize, &kidReflowInput,
  842. wm, kidOrigin, containerSize, 0);
  843. nsTableFrame::InvalidateTableFrame(firstKid, origRect, origVisualOverflow,
  844. firstReflow);
  845. // first, compute the bsize which can be set w/o being restricted by
  846. // available bsize
  847. LogicalSize cellSize(wm);
  848. cellSize.BSize(wm) = kidSize.BSize(wm);
  849. if (NS_UNCONSTRAINEDSIZE != cellSize.BSize(wm)) {
  850. cellSize.BSize(wm) += borderPadding.BStartEnd(wm);
  851. }
  852. // next determine the cell's isize
  853. cellSize.ISize(wm) = kidSize.ISize(wm); // at this point, we've factored in the cell's style attributes
  854. // factor in border and padding
  855. if (NS_UNCONSTRAINEDSIZE != cellSize.ISize(wm)) {
  856. cellSize.ISize(wm) += borderPadding.IStartEnd(wm);
  857. }
  858. // set the cell's desired size and max element size
  859. aDesiredSize.SetSize(wm, cellSize);
  860. // the overflow area will be computed when BlockDirAlignChild() gets called
  861. if (aReflowInput.mFlags.mSpecialBSizeReflow) {
  862. if (aDesiredSize.BSize(wm) > BSize(wm)) {
  863. // set a bit indicating that the pct bsize contents exceeded
  864. // the height that they could honor in the pass 2 reflow
  865. SetHasPctOverBSize(true);
  866. }
  867. if (NS_UNCONSTRAINEDSIZE == aReflowInput.AvailableBSize()) {
  868. aDesiredSize.BSize(wm) = BSize(wm);
  869. }
  870. }
  871. // If our parent is in initial reflow, it'll handle invalidating our
  872. // entire overflow rect.
  873. if (!GetParent()->HasAnyStateBits(NS_FRAME_FIRST_REFLOW) &&
  874. nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) {
  875. InvalidateFrame();
  876. }
  877. // remember the desired size for this reflow
  878. SetDesiredSize(aDesiredSize);
  879. // Any absolutely-positioned children will get reflowed in
  880. // nsFrame::FixupPositionedTableParts in another pass, so propagate our
  881. // dirtiness to them before our parent clears our dirty bits.
  882. PushDirtyBitToAbsoluteFrames();
  883. NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
  884. }
  885. /* ----- global methods ----- */
  886. NS_QUERYFRAME_HEAD(nsTableCellFrame)
  887. NS_QUERYFRAME_ENTRY(nsTableCellFrame)
  888. NS_QUERYFRAME_ENTRY(nsITableCellLayout)
  889. NS_QUERYFRAME_ENTRY(nsIPercentBSizeObserver)
  890. NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
  891. #ifdef ACCESSIBILITY
  892. a11y::AccType
  893. nsTableCellFrame::AccessibleType()
  894. {
  895. return a11y::eHTMLTableCellType;
  896. }
  897. #endif
  898. /* This is primarily for editor access via nsITableLayout */
  899. NS_IMETHODIMP
  900. nsTableCellFrame::GetCellIndexes(int32_t &aRowIndex, int32_t &aColIndex)
  901. {
  902. aRowIndex = RowIndex();
  903. aColIndex = mColIndex;
  904. return NS_OK;
  905. }
  906. nsTableCellFrame*
  907. NS_NewTableCellFrame(nsIPresShell* aPresShell,
  908. nsStyleContext* aContext,
  909. nsTableFrame* aTableFrame)
  910. {
  911. if (aTableFrame->IsBorderCollapse())
  912. return new (aPresShell) nsBCTableCellFrame(aContext, aTableFrame);
  913. else
  914. return new (aPresShell) nsTableCellFrame(aContext, aTableFrame);
  915. }
  916. NS_IMPL_FRAMEARENA_HELPERS(nsBCTableCellFrame)
  917. LogicalMargin
  918. nsTableCellFrame::GetBorderWidth(WritingMode aWM) const
  919. {
  920. return LogicalMargin(aWM, StyleBorder()->GetComputedBorder());
  921. }
  922. nsIAtom*
  923. nsTableCellFrame::GetType() const
  924. {
  925. return nsGkAtoms::tableCellFrame;
  926. }
  927. #ifdef DEBUG_FRAME_DUMP
  928. nsresult
  929. nsTableCellFrame::GetFrameName(nsAString& aResult) const
  930. {
  931. return MakeFrameName(NS_LITERAL_STRING("TableCell"), aResult);
  932. }
  933. #endif
  934. // nsBCTableCellFrame
  935. nsBCTableCellFrame::nsBCTableCellFrame(nsStyleContext* aContext,
  936. nsTableFrame* aTableFrame)
  937. : nsTableCellFrame(aContext, aTableFrame)
  938. {
  939. mBStartBorder = mIEndBorder = mBEndBorder = mIStartBorder = 0;
  940. }
  941. nsBCTableCellFrame::~nsBCTableCellFrame()
  942. {
  943. }
  944. nsIAtom*
  945. nsBCTableCellFrame::GetType() const
  946. {
  947. return nsGkAtoms::bcTableCellFrame;
  948. }
  949. /* virtual */ nsMargin
  950. nsBCTableCellFrame::GetUsedBorder() const
  951. {
  952. WritingMode wm = GetWritingMode();
  953. return GetBorderWidth(wm).GetPhysicalMargin(wm);
  954. }
  955. #ifdef DEBUG_FRAME_DUMP
  956. nsresult
  957. nsBCTableCellFrame::GetFrameName(nsAString& aResult) const
  958. {
  959. return MakeFrameName(NS_LITERAL_STRING("BCTableCell"), aResult);
  960. }
  961. #endif
  962. LogicalMargin
  963. nsBCTableCellFrame::GetBorderWidth(WritingMode aWM) const
  964. {
  965. int32_t pixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
  966. return LogicalMargin(aWM,
  967. BC_BORDER_END_HALF_COORD(pixelsToTwips, mBStartBorder),
  968. BC_BORDER_START_HALF_COORD(pixelsToTwips, mIEndBorder),
  969. BC_BORDER_START_HALF_COORD(pixelsToTwips, mBEndBorder),
  970. BC_BORDER_END_HALF_COORD(pixelsToTwips, mIStartBorder));
  971. }
  972. BCPixelSize
  973. nsBCTableCellFrame::GetBorderWidth(LogicalSide aSide) const
  974. {
  975. switch(aSide) {
  976. case eLogicalSideBStart:
  977. return BC_BORDER_END_HALF(mBStartBorder);
  978. case eLogicalSideIEnd:
  979. return BC_BORDER_START_HALF(mIEndBorder);
  980. case eLogicalSideBEnd:
  981. return BC_BORDER_START_HALF(mBEndBorder);
  982. default:
  983. return BC_BORDER_END_HALF(mIStartBorder);
  984. }
  985. }
  986. void
  987. nsBCTableCellFrame::SetBorderWidth(LogicalSide aSide, BCPixelSize aValue)
  988. {
  989. switch(aSide) {
  990. case eLogicalSideBStart:
  991. mBStartBorder = aValue;
  992. break;
  993. case eLogicalSideIEnd:
  994. mIEndBorder = aValue;
  995. break;
  996. case eLogicalSideBEnd:
  997. mBEndBorder = aValue;
  998. break;
  999. default:
  1000. mIStartBorder = aValue;
  1001. }
  1002. }
  1003. /* virtual */ nsMargin
  1004. nsBCTableCellFrame::GetBorderOverflow()
  1005. {
  1006. WritingMode wm = GetWritingMode();
  1007. int32_t p2t = nsPresContext::AppUnitsPerCSSPixel();
  1008. LogicalMargin halfBorder(wm,
  1009. BC_BORDER_START_HALF_COORD(p2t, mBStartBorder),
  1010. BC_BORDER_END_HALF_COORD(p2t, mIEndBorder),
  1011. BC_BORDER_END_HALF_COORD(p2t, mBEndBorder),
  1012. BC_BORDER_START_HALF_COORD(p2t, mIStartBorder));
  1013. return halfBorder.GetPhysicalMargin(wm);
  1014. }
  1015. DrawResult
  1016. nsBCTableCellFrame::PaintBackground(nsRenderingContext& aRenderingContext,
  1017. const nsRect& aDirtyRect,
  1018. nsPoint aPt,
  1019. uint32_t aFlags)
  1020. {
  1021. // make border-width reflect the half of the border-collapse
  1022. // assigned border that's inside the cell
  1023. WritingMode wm = GetWritingMode();
  1024. nsMargin borderWidth = GetBorderWidth(wm).GetPhysicalMargin(wm);
  1025. nsStyleBorder myBorder(*StyleBorder());
  1026. NS_FOR_CSS_SIDES(side) {
  1027. myBorder.SetBorderWidth(side, borderWidth.Side(side));
  1028. }
  1029. // bypassing nsCSSRendering::PaintBackground is safe because this kind
  1030. // of frame cannot be used for the root element
  1031. nsRect rect(aPt, GetSize());
  1032. nsCSSRendering::PaintBGParams params =
  1033. nsCSSRendering::PaintBGParams::ForAllLayers(*PresContext(),
  1034. aRenderingContext, aDirtyRect,
  1035. rect, this,
  1036. aFlags);
  1037. return nsCSSRendering::PaintBackgroundWithSC(params, StyleContext(), myBorder);
  1038. }