1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Pierre Phaneuf <pp@ludusdesign.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 : #include "nsTableFrame.h"
39 : #include "nsTableColFrame.h"
40 : #include "nsTableCellFrame.h"
41 : #include "nsTableRowGroupFrame.h"
42 : #include "nsTablePainter.h"
43 : #include "nsStyleContext.h"
44 : #include "nsStyleConsts.h"
45 : #include "nsPresContext.h"
46 : #include "nsRenderingContext.h"
47 : #include "nsCSSRendering.h"
48 : #include "nsIContent.h"
49 : #include "nsGenericHTMLElement.h"
50 : #include "nsHTMLParts.h"
51 : #include "nsGkAtoms.h"
52 : #include "nsIPresShell.h"
53 : #include "nsCOMPtr.h"
54 : #include "nsIDOMHTMLTableCellElement.h"
55 : #ifdef ACCESSIBILITY
56 : #include "nsAccessibilityService.h"
57 : #endif
58 : #include "nsIServiceManager.h"
59 : #include "nsIDOMNode.h"
60 : #include "nsINameSpaceManager.h"
61 : #include "nsDisplayList.h"
62 : #include "nsLayoutUtils.h"
63 : #include "nsTextFrame.h"
64 :
65 : //TABLECELL SELECTION
66 : #include "nsFrameSelection.h"
67 : #include "mozilla/LookAndFeel.h"
68 :
69 : using namespace mozilla;
70 :
71 :
72 0 : nsTableCellFrame::nsTableCellFrame(nsStyleContext* aContext) :
73 0 : nsContainerFrame(aContext)
74 : {
75 0 : mColIndex = 0;
76 0 : mPriorAvailWidth = 0;
77 :
78 0 : SetContentEmpty(false);
79 0 : SetHasPctOverHeight(false);
80 0 : }
81 :
82 0 : nsTableCellFrame::~nsTableCellFrame()
83 : {
84 0 : }
85 :
86 0 : NS_IMPL_FRAMEARENA_HELPERS(nsTableCellFrame)
87 :
88 : nsTableCellFrame*
89 0 : nsTableCellFrame::GetNextCell() const
90 : {
91 0 : nsIFrame* childFrame = GetNextSibling();
92 0 : while (childFrame) {
93 0 : nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
94 0 : if (cellFrame) {
95 0 : return cellFrame;
96 : }
97 0 : childFrame = childFrame->GetNextSibling();
98 : }
99 0 : return nsnull;
100 : }
101 :
102 : NS_IMETHODIMP
103 0 : nsTableCellFrame::Init(nsIContent* aContent,
104 : nsIFrame* aParent,
105 : nsIFrame* aPrevInFlow)
106 : {
107 : // Let the base class do its initialization
108 0 : nsresult rv = nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
109 :
110 0 : if (aPrevInFlow) {
111 : // Set the column index
112 0 : nsTableCellFrame* cellFrame = (nsTableCellFrame*)aPrevInFlow;
113 : PRInt32 colIndex;
114 0 : cellFrame->GetColIndex(colIndex);
115 0 : SetColIndex(colIndex);
116 : }
117 :
118 0 : return rv;
119 : }
120 :
121 : // nsIPercentHeightObserver methods
122 :
123 : void
124 0 : nsTableCellFrame::NotifyPercentHeight(const nsHTMLReflowState& aReflowState)
125 : {
126 : // nsHTMLReflowState ensures the mCBReflowState of blocks inside a
127 : // cell is the cell frame, not the inner-cell block, and that the
128 : // containing block of an inner table is the containing block of its
129 : // outer table.
130 : // XXXldb Given the now-stricter |NeedsToObserve|, many if not all of
131 : // these tests are probably unnecessary.
132 :
133 : // Maybe the cell reflow state; we sure if we're inside the |if|.
134 0 : const nsHTMLReflowState *cellRS = aReflowState.mCBReflowState;
135 :
136 0 : if (cellRS && cellRS->frame == this &&
137 0 : (cellRS->ComputedHeight() == NS_UNCONSTRAINEDSIZE ||
138 0 : cellRS->ComputedHeight() == 0)) { // XXXldb Why 0?
139 : // This is a percentage height on a frame whose percentage heights
140 : // are based on the height of the cell, since its containing block
141 : // is the inner cell frame.
142 :
143 : // We'll only honor the percent height if sibling-cells/ancestors
144 : // have specified/pct height. (Also, siblings only count for this if
145 : // both this cell and the sibling cell span exactly 1 row.)
146 :
147 0 : if (nsTableFrame::AncestorsHaveStyleHeight(*cellRS) ||
148 0 : (nsTableFrame::GetTableFrame(this)->GetEffectiveRowSpan(*this) == 1 &&
149 0 : (cellRS->parentReflowState->frame->GetStateBits() &
150 : NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT))) {
151 :
152 0 : for (const nsHTMLReflowState *rs = aReflowState.parentReflowState;
153 : rs != cellRS;
154 : rs = rs->parentReflowState) {
155 0 : rs->frame->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
156 : }
157 :
158 0 : nsTableFrame::RequestSpecialHeightReflow(*cellRS);
159 : }
160 : }
161 0 : }
162 :
163 : // The cell needs to observe its block and things inside its block but nothing below that
164 : bool
165 0 : nsTableCellFrame::NeedsToObserve(const nsHTMLReflowState& aReflowState)
166 : {
167 0 : const nsHTMLReflowState *rs = aReflowState.parentReflowState;
168 0 : if (!rs)
169 0 : return false;
170 0 : if (rs->frame == this) {
171 : // We always observe the child block. It will never send any
172 : // notifications, but we need this so that the observer gets
173 : // propagated to its kids.
174 0 : return true;
175 : }
176 0 : rs = rs->parentReflowState;
177 0 : if (!rs) {
178 0 : return false;
179 : }
180 :
181 : // We always need to let the percent height observer be propagated
182 : // from an outer table frame to an inner table frame.
183 0 : nsIAtom *fType = aReflowState.frame->GetType();
184 0 : if (fType == nsGkAtoms::tableFrame) {
185 0 : return true;
186 : }
187 :
188 : // We need the observer to be propagated to all children of the cell
189 : // (i.e., children of the child block) in quirks mode, but only to
190 : // tables in standards mode.
191 : return rs->frame == this &&
192 0 : (PresContext()->CompatibilityMode() == eCompatibility_NavQuirks ||
193 0 : fType == nsGkAtoms::tableOuterFrame);
194 : }
195 :
196 : nsresult
197 0 : nsTableCellFrame::GetRowIndex(PRInt32 &aRowIndex) const
198 : {
199 : nsresult result;
200 0 : nsTableRowFrame* row = static_cast<nsTableRowFrame*>(GetParent());
201 0 : if (row) {
202 0 : aRowIndex = row->GetRowIndex();
203 0 : result = NS_OK;
204 : }
205 : else {
206 0 : aRowIndex = 0;
207 0 : result = NS_ERROR_NOT_INITIALIZED;
208 : }
209 0 : return result;
210 : }
211 :
212 : nsresult
213 0 : nsTableCellFrame::GetColIndex(PRInt32 &aColIndex) const
214 : {
215 0 : if (GetPrevInFlow()) {
216 0 : return ((nsTableCellFrame*)GetFirstInFlow())->GetColIndex(aColIndex);
217 : }
218 : else {
219 0 : aColIndex = mColIndex;
220 0 : return NS_OK;
221 : }
222 : }
223 :
224 : NS_IMETHODIMP
225 0 : nsTableCellFrame::AttributeChanged(PRInt32 aNameSpaceID,
226 : nsIAtom* aAttribute,
227 : PRInt32 aModType)
228 : {
229 : // We need to recalculate in this case because of the nowrap quirk in
230 : // BasicTableLayoutStrategy
231 0 : if (aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::nowrap &&
232 0 : PresContext()->CompatibilityMode() == eCompatibility_NavQuirks) {
233 0 : PresContext()->PresShell()->
234 0 : FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
235 : }
236 : // let the table frame decide what to do
237 0 : nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
238 0 : tableFrame->AttributeChangedFor(this, mContent, aAttribute);
239 0 : return NS_OK;
240 : }
241 :
242 : /* virtual */ void
243 0 : nsTableCellFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
244 : {
245 0 : if (!aOldStyleContext) //avoid this on init
246 0 : return;
247 :
248 0 : nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
249 0 : if (tableFrame->IsBorderCollapse() &&
250 0 : tableFrame->BCRecalcNeeded(aOldStyleContext, GetStyleContext())) {
251 : PRInt32 colIndex, rowIndex;
252 0 : GetColIndex(colIndex);
253 0 : GetRowIndex(rowIndex);
254 : // row span needs to be clamped as we do not create rows in the cellmap
255 : // which do not have cells originating in them
256 0 : nsIntRect damageArea(colIndex, rowIndex, GetColSpan(),
257 0 : NS_MIN(GetRowSpan(), tableFrame->GetRowCount() - rowIndex));
258 0 : tableFrame->AddBCDamageArea(damageArea);
259 : }
260 : }
261 :
262 :
263 : NS_IMETHODIMP
264 0 : nsTableCellFrame::AppendFrames(ChildListID aListID,
265 : nsFrameList& aFrameList)
266 : {
267 0 : NS_PRECONDITION(false, "unsupported operation");
268 0 : return NS_ERROR_NOT_IMPLEMENTED;
269 : }
270 :
271 : NS_IMETHODIMP
272 0 : nsTableCellFrame::InsertFrames(ChildListID aListID,
273 : nsIFrame* aPrevFrame,
274 : nsFrameList& aFrameList)
275 : {
276 0 : NS_PRECONDITION(false, "unsupported operation");
277 0 : return NS_ERROR_NOT_IMPLEMENTED;
278 : }
279 :
280 : NS_IMETHODIMP
281 0 : nsTableCellFrame::RemoveFrame(ChildListID aListID,
282 : nsIFrame* aOldFrame)
283 : {
284 0 : NS_PRECONDITION(false, "unsupported operation");
285 0 : return NS_ERROR_NOT_IMPLEMENTED;
286 : }
287 :
288 0 : void nsTableCellFrame::SetColIndex(PRInt32 aColIndex)
289 : {
290 0 : mColIndex = aColIndex;
291 0 : }
292 :
293 : /* virtual */ nsMargin
294 0 : nsTableCellFrame::GetUsedMargin() const
295 : {
296 0 : return nsMargin(0,0,0,0);
297 : }
298 :
299 : //ASSURE DIFFERENT COLORS for selection
300 0 : inline nscolor EnsureDifferentColors(nscolor colorA, nscolor colorB)
301 : {
302 0 : if (colorA == colorB)
303 : {
304 : nscolor res;
305 : res = NS_RGB(NS_GET_R(colorA) ^ 0xff,
306 : NS_GET_G(colorA) ^ 0xff,
307 0 : NS_GET_B(colorA) ^ 0xff);
308 0 : return res;
309 : }
310 0 : return colorA;
311 : }
312 :
313 : void
314 0 : nsTableCellFrame::DecorateForSelection(nsRenderingContext& aRenderingContext,
315 : nsPoint aPt)
316 : {
317 0 : NS_ASSERTION(IsSelected(), "Should only be called for selected cells");
318 : PRInt16 displaySelection;
319 0 : nsPresContext* presContext = PresContext();
320 0 : displaySelection = DisplaySelection(presContext);
321 0 : if (displaySelection) {
322 : nsRefPtr<nsFrameSelection> frameSelection =
323 0 : presContext->PresShell()->FrameSelection();
324 :
325 0 : if (frameSelection->GetTableCellSelection()) {
326 : nscolor bordercolor;
327 0 : if (displaySelection == nsISelectionController::SELECTION_DISABLED) {
328 0 : bordercolor = NS_RGB(176,176,176);// disabled color
329 : }
330 : else {
331 : bordercolor =
332 0 : LookAndFeel::GetColor(LookAndFeel::eColorID_TextSelectBackground);
333 : }
334 0 : nscoord threePx = nsPresContext::CSSPixelsToAppUnits(3);
335 0 : if ((mRect.width > threePx) && (mRect.height > threePx))
336 : {
337 : //compare bordercolor to ((nsStyleColor *)myColor)->mBackgroundColor)
338 : bordercolor = EnsureDifferentColors(bordercolor,
339 0 : GetStyleBackground()->mBackgroundColor);
340 : nsRenderingContext::AutoPushTranslation
341 0 : translate(&aRenderingContext, aPt);
342 0 : nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
343 :
344 0 : aRenderingContext.SetColor(bordercolor);
345 0 : aRenderingContext.DrawLine(onePixel, 0, mRect.width, 0);
346 0 : aRenderingContext.DrawLine(0, onePixel, 0, mRect.height);
347 0 : aRenderingContext.DrawLine(onePixel, mRect.height, mRect.width, mRect.height);
348 0 : aRenderingContext.DrawLine(mRect.width, onePixel, mRect.width, mRect.height);
349 : //middle
350 : aRenderingContext.DrawRect(onePixel, onePixel, mRect.width-onePixel,
351 0 : mRect.height-onePixel);
352 : //shading
353 : aRenderingContext.DrawLine(2*onePixel, mRect.height-2*onePixel,
354 0 : mRect.width-onePixel, mRect.height- (2*onePixel));
355 : aRenderingContext.DrawLine(mRect.width - (2*onePixel), 2*onePixel,
356 0 : mRect.width - (2*onePixel), mRect.height-onePixel);
357 : }
358 : }
359 : }
360 0 : }
361 :
362 : void
363 0 : nsTableCellFrame::PaintBackground(nsRenderingContext& aRenderingContext,
364 : const nsRect& aDirtyRect,
365 : nsPoint aPt,
366 : PRUint32 aFlags)
367 : {
368 0 : nsRect rect(aPt, GetSize());
369 : nsCSSRendering::PaintBackground(PresContext(), aRenderingContext, this,
370 0 : aDirtyRect, rect, aFlags);
371 0 : }
372 :
373 : // Called by nsTablePainter
374 : void
375 0 : nsTableCellFrame::PaintCellBackground(nsRenderingContext& aRenderingContext,
376 : const nsRect& aDirtyRect, nsPoint aPt,
377 : PRUint32 aFlags)
378 : {
379 0 : if (!GetStyleVisibility()->IsVisible())
380 0 : return;
381 :
382 0 : PaintBackground(aRenderingContext, aDirtyRect, aPt, aFlags);
383 : }
384 :
385 : class nsDisplayTableCellBackground : public nsDisplayTableItem {
386 : public:
387 0 : nsDisplayTableCellBackground(nsDisplayListBuilder* aBuilder,
388 : nsTableCellFrame* aFrame) :
389 0 : nsDisplayTableItem(aBuilder, aFrame) {
390 0 : MOZ_COUNT_CTOR(nsDisplayTableCellBackground);
391 0 : }
392 : #ifdef NS_BUILD_REFCNT_LOGGING
393 0 : virtual ~nsDisplayTableCellBackground() {
394 0 : MOZ_COUNT_DTOR(nsDisplayTableCellBackground);
395 0 : }
396 : #endif
397 :
398 0 : virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
399 : HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
400 0 : aOutFrames->AppendElement(mFrame);
401 0 : }
402 : virtual void Paint(nsDisplayListBuilder* aBuilder,
403 : nsRenderingContext* aCtx);
404 : virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
405 :
406 0 : NS_DISPLAY_DECL_NAME("TableCellBackground", TYPE_TABLE_CELL_BACKGROUND)
407 : };
408 :
409 0 : void nsDisplayTableCellBackground::Paint(nsDisplayListBuilder* aBuilder,
410 : nsRenderingContext* aCtx)
411 : {
412 : static_cast<nsTableCellFrame*>(mFrame)->
413 0 : PaintBackground(*aCtx, mVisibleRect, ToReferenceFrame(),
414 0 : aBuilder->GetBackgroundPaintFlags());
415 0 : }
416 :
417 : nsRect
418 0 : nsDisplayTableCellBackground::GetBounds(nsDisplayListBuilder* aBuilder)
419 : {
420 : // revert from nsDisplayTableItem's implementation ... cell backgrounds
421 : // don't overflow the cell
422 0 : return nsDisplayItem::GetBounds(aBuilder);
423 : }
424 :
425 : static void
426 0 : PaintTableCellSelection(nsIFrame* aFrame, nsRenderingContext* aCtx,
427 : const nsRect& aRect, nsPoint aPt)
428 : {
429 0 : static_cast<nsTableCellFrame*>(aFrame)->DecorateForSelection(*aCtx, aPt);
430 0 : }
431 :
432 : NS_IMETHODIMP
433 0 : nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
434 : const nsRect& aDirtyRect,
435 : const nsDisplayListSet& aLists)
436 : {
437 0 : DO_GLOBAL_REFLOW_COUNT_DSP("nsTableCellFrame");
438 0 : if (IsVisibleInSelection(aBuilder)) {
439 0 : nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
440 0 : PRInt32 emptyCellStyle = GetContentEmpty() && !tableFrame->IsBorderCollapse() ?
441 0 : GetStyleTableBorder()->mEmptyCells
442 0 : : NS_STYLE_TABLE_EMPTY_CELLS_SHOW;
443 : // take account of 'empty-cells'
444 0 : if (GetStyleVisibility()->IsVisible() &&
445 : (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != emptyCellStyle)) {
446 :
447 :
448 0 : bool isRoot = aBuilder->IsAtRootOfPseudoStackingContext();
449 0 : if (!isRoot) {
450 0 : nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem();
451 0 : if (currentItem) {
452 0 : currentItem->UpdateForFrameBackground(this);
453 : }
454 : }
455 :
456 : // display outset box-shadows if we need to.
457 0 : bool hasBoxShadow = !!(GetStyleBorder()->mBoxShadow);
458 0 : if (hasBoxShadow) {
459 : nsresult rv = aLists.BorderBackground()->AppendNewToTop(
460 0 : new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, this));
461 0 : NS_ENSURE_SUCCESS(rv, rv);
462 : }
463 :
464 : // display background if we need to.
465 0 : if (aBuilder->IsForEventDelivery() ||
466 0 : (((!tableFrame->IsBorderCollapse() || isRoot) &&
467 0 : (!GetStyleBackground()->IsTransparent() || GetStyleDisplay()->mAppearance)))) {
468 : // The cell background was not painted by the nsTablePainter,
469 : // so we need to do it. We have special background processing here
470 : // so we need to duplicate some code from nsFrame::DisplayBorderBackgroundOutline
471 : nsDisplayTableItem* item =
472 0 : new (aBuilder) nsDisplayTableCellBackground(aBuilder, this);
473 0 : nsresult rv = aLists.BorderBackground()->AppendNewToTop(item);
474 0 : NS_ENSURE_SUCCESS(rv, rv);
475 0 : item->UpdateForFrameBackground(this);
476 : }
477 :
478 : // display inset box-shadows if we need to.
479 0 : if (hasBoxShadow) {
480 : nsresult rv = aLists.BorderBackground()->AppendNewToTop(
481 0 : new (aBuilder) nsDisplayBoxShadowInner(aBuilder, this));
482 0 : NS_ENSURE_SUCCESS(rv, rv);
483 : }
484 :
485 : // display borders if we need to
486 0 : if (!tableFrame->IsBorderCollapse() && HasBorder() &&
487 : emptyCellStyle == NS_STYLE_TABLE_EMPTY_CELLS_SHOW) {
488 : nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
489 0 : nsDisplayBorder(aBuilder, this));
490 0 : NS_ENSURE_SUCCESS(rv, rv);
491 : }
492 :
493 : // and display the selection border if we need to
494 0 : if (IsSelected()) {
495 : nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
496 : nsDisplayGeneric(aBuilder, this, ::PaintTableCellSelection,
497 : "TableCellSelection",
498 0 : nsDisplayItem::TYPE_TABLE_CELL_SELECTION));
499 0 : NS_ENSURE_SUCCESS(rv, rv);
500 : }
501 : }
502 :
503 : // the 'empty-cells' property has no effect on 'outline'
504 0 : nsresult rv = DisplayOutline(aBuilder, aLists);
505 0 : NS_ENSURE_SUCCESS(rv, rv);
506 : }
507 :
508 : // Push a null 'current table item' so that descendant tables can't
509 : // accidentally mess with our table
510 0 : nsAutoPushCurrentTableItem pushTableItem;
511 0 : pushTableItem.Push(aBuilder, nsnull);
512 :
513 0 : nsIFrame* kid = mFrames.FirstChild();
514 0 : NS_ASSERTION(kid && !kid->GetNextSibling(), "Table cells should have just one child");
515 : // The child's background will go in our BorderBackground() list.
516 : // This isn't a problem since it won't have a real background except for
517 : // event handling. We do not call BuildDisplayListForNonBlockChildren
518 : // because that/ would put the child's background in the Content() list
519 : // which isn't right (e.g., would end up on top of our child floats for
520 : // event handling).
521 0 : return BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
522 : }
523 :
524 : PRIntn
525 0 : nsTableCellFrame::GetSkipSides() const
526 : {
527 0 : PRIntn skip = 0;
528 0 : if (nsnull != GetPrevInFlow()) {
529 0 : skip |= 1 << NS_SIDE_TOP;
530 : }
531 0 : if (nsnull != GetNextInFlow()) {
532 0 : skip |= 1 << NS_SIDE_BOTTOM;
533 : }
534 0 : return skip;
535 : }
536 :
537 : /* virtual */ nsMargin
538 0 : nsTableCellFrame::GetBorderOverflow()
539 : {
540 0 : return nsMargin(0, 0, 0, 0);
541 : }
542 :
543 : // Align the cell's child frame within the cell
544 :
545 0 : void nsTableCellFrame::VerticallyAlignChild(nscoord aMaxAscent)
546 : {
547 : /* It's the 'border-collapse' on the table that matters */
548 0 : nsMargin borderPadding = GetUsedBorderAndPadding();
549 :
550 0 : nscoord topInset = borderPadding.top;
551 0 : nscoord bottomInset = borderPadding.bottom;
552 :
553 0 : PRUint8 verticalAlignFlags = GetVerticalAlign();
554 :
555 0 : nscoord height = mRect.height;
556 0 : nsIFrame* firstKid = mFrames.FirstChild();
557 0 : NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame");
558 0 : nsRect kidRect = firstKid->GetRect();
559 0 : nscoord childHeight = kidRect.height;
560 :
561 : // Vertically align the child
562 0 : nscoord kidYTop = 0;
563 0 : switch (verticalAlignFlags)
564 : {
565 : case NS_STYLE_VERTICAL_ALIGN_BASELINE:
566 : // Align the baselines of the child frame with the baselines of
567 : // other children in the same row which have 'vertical-align: baseline'
568 0 : kidYTop = topInset + aMaxAscent - GetCellBaseline();
569 0 : break;
570 :
571 : case NS_STYLE_VERTICAL_ALIGN_TOP:
572 : // Align the top of the child frame with the top of the content area,
573 0 : kidYTop = topInset;
574 0 : break;
575 :
576 : case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
577 : // Align the bottom of the child frame with the bottom of the content area,
578 0 : kidYTop = height - childHeight - bottomInset;
579 0 : break;
580 :
581 : default:
582 : case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
583 : // Align the middle of the child frame with the middle of the content area,
584 0 : kidYTop = (height - childHeight - bottomInset + topInset) / 2;
585 : }
586 : // if the content is larger than the cell height align from top
587 0 : kidYTop = NS_MAX(0, kidYTop);
588 :
589 0 : if (kidYTop != kidRect.y) {
590 : // Invalidate at the old position first
591 0 : firstKid->InvalidateFrameSubtree();
592 : }
593 :
594 0 : firstKid->SetPosition(nsPoint(kidRect.x, kidYTop));
595 0 : nsHTMLReflowMetrics desiredSize;
596 0 : desiredSize.width = mRect.width;
597 0 : desiredSize.height = mRect.height;
598 :
599 0 : nsRect overflow(nsPoint(0,0), GetSize());
600 0 : overflow.Inflate(GetBorderOverflow());
601 0 : desiredSize.mOverflowAreas.SetAllTo(overflow);
602 0 : ConsiderChildOverflow(desiredSize.mOverflowAreas, firstKid);
603 0 : FinishAndStoreOverflow(&desiredSize);
604 0 : if (kidYTop != kidRect.y) {
605 : // Make sure any child views are correctly positioned. We know the inner table
606 : // cell won't have a view
607 0 : nsContainerFrame::PositionChildViews(firstKid);
608 :
609 : // Invalidate new overflow rect
610 0 : firstKid->InvalidateFrameSubtree();
611 : }
612 0 : if (HasView()) {
613 : nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this,
614 : GetView(),
615 0 : desiredSize.VisualOverflow(), 0);
616 : }
617 0 : }
618 :
619 : bool
620 0 : nsTableCellFrame::UpdateOverflow()
621 : {
622 0 : nsRect bounds(nsPoint(0,0), GetSize());
623 0 : bounds.Inflate(GetBorderOverflow());
624 0 : nsOverflowAreas overflowAreas(bounds, bounds);
625 :
626 0 : nsLayoutUtils::UnionChildOverflow(this, overflowAreas);
627 :
628 0 : return FinishAndStoreOverflow(overflowAreas, GetSize());
629 : }
630 :
631 : // Per CSS 2.1, we map 'sub', 'super', 'text-top', 'text-bottom',
632 : // length, percentage, and calc() values to 'baseline'.
633 : PRUint8
634 0 : nsTableCellFrame::GetVerticalAlign() const
635 : {
636 0 : const nsStyleCoord& verticalAlign = GetStyleTextReset()->mVerticalAlign;
637 0 : if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) {
638 0 : PRUint8 value = verticalAlign.GetIntValue();
639 0 : if (value == NS_STYLE_VERTICAL_ALIGN_TOP ||
640 : value == NS_STYLE_VERTICAL_ALIGN_MIDDLE ||
641 : value == NS_STYLE_VERTICAL_ALIGN_BOTTOM) {
642 0 : return value;
643 : }
644 : }
645 0 : return NS_STYLE_VERTICAL_ALIGN_BASELINE;
646 : }
647 :
648 : bool
649 0 : nsTableCellFrame::CellHasVisibleContent(nscoord height,
650 : nsTableFrame* tableFrame,
651 : nsIFrame* kidFrame)
652 : {
653 : // see http://www.w3.org/TR/CSS21/tables.html#empty-cells
654 0 : if (height > 0)
655 0 : return true;
656 0 : if (tableFrame->IsBorderCollapse())
657 0 : return true;
658 0 : nsIFrame* innerFrame = kidFrame->GetFirstPrincipalChild();
659 0 : while(innerFrame) {
660 0 : nsIAtom* frameType = innerFrame->GetType();
661 0 : if (nsGkAtoms::textFrame == frameType) {
662 0 : nsTextFrame* textFrame = static_cast<nsTextFrame*>(innerFrame);
663 0 : if (textFrame->HasNoncollapsedCharacters())
664 0 : return true;
665 : }
666 0 : else if (nsGkAtoms::placeholderFrame != frameType) {
667 0 : return true;
668 : }
669 : else {
670 0 : nsIFrame *floatFrame = nsLayoutUtils::GetFloatFromPlaceholder(innerFrame);
671 0 : if (floatFrame)
672 0 : return true;
673 : }
674 0 : innerFrame = innerFrame->GetNextSibling();
675 : }
676 0 : return false;
677 : }
678 :
679 : nscoord
680 0 : nsTableCellFrame::GetCellBaseline() const
681 : {
682 : // Ignore the position of the inner frame relative to the cell frame
683 : // since we want the position as though the inner were top-aligned.
684 0 : nsIFrame *inner = mFrames.FirstChild();
685 0 : nscoord borderPadding = GetUsedBorderAndPadding().top;
686 : nscoord result;
687 0 : if (nsLayoutUtils::GetFirstLineBaseline(inner, &result))
688 0 : return result + borderPadding;
689 0 : return inner->GetContentRect().YMost() - inner->GetPosition().y +
690 0 : borderPadding;
691 : }
692 :
693 0 : PRInt32 nsTableCellFrame::GetRowSpan()
694 : {
695 0 : PRInt32 rowSpan=1;
696 0 : nsGenericHTMLElement *hc = nsGenericHTMLElement::FromContent(mContent);
697 :
698 : // Don't look at the content's rowspan if we're a pseudo cell
699 0 : if (hc && !GetStyleContext()->GetPseudo()) {
700 0 : const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::rowspan);
701 : // Note that we don't need to check the tag name, because only table cells
702 : // and table headers parse the "rowspan" attribute into an integer.
703 0 : if (attr && attr->Type() == nsAttrValue::eInteger) {
704 0 : rowSpan = attr->GetIntegerValue();
705 : }
706 : }
707 0 : return rowSpan;
708 : }
709 :
710 0 : PRInt32 nsTableCellFrame::GetColSpan()
711 : {
712 0 : PRInt32 colSpan=1;
713 0 : nsGenericHTMLElement *hc = nsGenericHTMLElement::FromContent(mContent);
714 :
715 : // Don't look at the content's colspan if we're a pseudo cell
716 0 : if (hc && !GetStyleContext()->GetPseudo()) {
717 0 : const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::colspan);
718 : // Note that we don't need to check the tag name, because only table cells
719 : // and table headers parse the "colspan" attribute into an integer.
720 0 : if (attr && attr->Type() == nsAttrValue::eInteger) {
721 0 : colSpan = attr->GetIntegerValue();
722 : }
723 : }
724 0 : return colSpan;
725 : }
726 :
727 : /* virtual */ nscoord
728 0 : nsTableCellFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
729 : {
730 0 : nscoord result = 0;
731 0 : DISPLAY_MIN_WIDTH(this, result);
732 :
733 0 : nsIFrame *inner = mFrames.FirstChild();
734 : result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner,
735 0 : nsLayoutUtils::MIN_WIDTH);
736 0 : return result;
737 : }
738 :
739 : /* virtual */ nscoord
740 0 : nsTableCellFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
741 : {
742 0 : nscoord result = 0;
743 0 : DISPLAY_PREF_WIDTH(this, result);
744 :
745 0 : nsIFrame *inner = mFrames.FirstChild();
746 : result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner,
747 0 : nsLayoutUtils::PREF_WIDTH);
748 0 : return result;
749 : }
750 :
751 : /* virtual */ nsIFrame::IntrinsicWidthOffsetData
752 0 : nsTableCellFrame::IntrinsicWidthOffsets(nsRenderingContext* aRenderingContext)
753 : {
754 : IntrinsicWidthOffsetData result =
755 0 : nsContainerFrame::IntrinsicWidthOffsets(aRenderingContext);
756 :
757 0 : result.hMargin = 0;
758 0 : result.hPctMargin = 0;
759 :
760 0 : nsMargin border;
761 0 : GetBorderWidth(border);
762 0 : result.hBorder = border.LeftRight();
763 :
764 : return result;
765 : }
766 :
767 : #ifdef DEBUG
768 : #define PROBABLY_TOO_LARGE 1000000
769 : static
770 0 : void DebugCheckChildSize(nsIFrame* aChild,
771 : nsHTMLReflowMetrics& aMet,
772 : nsSize& aAvailSize)
773 : {
774 0 : if ((aMet.width < 0) || (aMet.width > PROBABLY_TOO_LARGE)) {
775 : printf("WARNING: cell content %p has large width %d \n",
776 0 : static_cast<void*>(aChild), PRInt32(aMet.width));
777 : }
778 0 : }
779 : #endif
780 :
781 : // the computed height for the cell, which descendants use for percent height calculations
782 : // it is the height (minus border, padding) of the cell's first in flow during its final
783 : // reflow without an unconstrained height.
784 : static nscoord
785 0 : CalcUnpaginagedHeight(nsPresContext* aPresContext,
786 : nsTableCellFrame& aCellFrame,
787 : nsTableFrame& aTableFrame,
788 : nscoord aVerticalBorderPadding)
789 : {
790 0 : const nsTableCellFrame* firstCellInFlow = (nsTableCellFrame*)aCellFrame.GetFirstInFlow();
791 0 : nsTableFrame* firstTableInFlow = (nsTableFrame*)aTableFrame.GetFirstInFlow();
792 : nsTableRowFrame* row
793 0 : = static_cast<nsTableRowFrame*>(firstCellInFlow->GetParent());
794 : nsTableRowGroupFrame* firstRGInFlow
795 0 : = static_cast<nsTableRowGroupFrame*>(row->GetParent());
796 :
797 : PRInt32 rowIndex;
798 0 : firstCellInFlow->GetRowIndex(rowIndex);
799 0 : PRInt32 rowSpan = aTableFrame.GetEffectiveRowSpan(*firstCellInFlow);
800 0 : nscoord cellSpacing = firstTableInFlow->GetCellSpacingX();
801 :
802 0 : nscoord computedHeight = ((rowSpan - 1) * cellSpacing) - aVerticalBorderPadding;
803 : PRInt32 rowX;
804 0 : for (row = firstRGInFlow->GetFirstRow(), rowX = 0; row; row = row->GetNextRow(), rowX++) {
805 0 : if (rowX > rowIndex + rowSpan - 1) {
806 0 : break;
807 : }
808 0 : else if (rowX >= rowIndex) {
809 0 : computedHeight += row->GetUnpaginatedHeight(aPresContext);
810 : }
811 : }
812 0 : return computedHeight;
813 : }
814 :
815 0 : NS_METHOD nsTableCellFrame::Reflow(nsPresContext* aPresContext,
816 : nsHTMLReflowMetrics& aDesiredSize,
817 : const nsHTMLReflowState& aReflowState,
818 : nsReflowStatus& aStatus)
819 : {
820 0 : DO_GLOBAL_REFLOW_COUNT("nsTableCellFrame");
821 0 : DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
822 :
823 0 : if (aReflowState.mFlags.mSpecialHeightReflow) {
824 0 : GetFirstInFlow()->AddStateBits(NS_TABLE_CELL_HAD_SPECIAL_REFLOW);
825 : }
826 :
827 : // see if a special height reflow needs to occur due to having a pct height
828 0 : nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState);
829 :
830 0 : aStatus = NS_FRAME_COMPLETE;
831 0 : nsSize availSize(aReflowState.availableWidth, aReflowState.availableHeight);
832 :
833 0 : nsMargin borderPadding = aReflowState.mComputedPadding;
834 0 : nsMargin border;
835 0 : GetBorderWidth(border);
836 0 : borderPadding += border;
837 :
838 0 : nscoord topInset = borderPadding.top;
839 0 : nscoord rightInset = borderPadding.right;
840 0 : nscoord bottomInset = borderPadding.bottom;
841 0 : nscoord leftInset = borderPadding.left;
842 :
843 : // reduce available space by insets, if we're in a constrained situation
844 0 : availSize.width -= leftInset + rightInset;
845 0 : if (NS_UNCONSTRAINEDSIZE != availSize.height)
846 0 : availSize.height -= topInset + bottomInset;
847 :
848 : // Try to reflow the child into the available space. It might not
849 : // fit or might need continuing.
850 0 : if (availSize.height < 0)
851 0 : availSize.height = 1;
852 :
853 0 : nsHTMLReflowMetrics kidSize(aDesiredSize.mFlags);
854 0 : kidSize.width = kidSize.height = 0;
855 0 : SetPriorAvailWidth(aReflowState.availableWidth);
856 0 : nsIFrame* firstKid = mFrames.FirstChild();
857 0 : NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame");
858 0 : nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
859 :
860 0 : if (aReflowState.mFlags.mSpecialHeightReflow) {
861 0 : const_cast<nsHTMLReflowState&>(aReflowState).SetComputedHeight(mRect.height - topInset - bottomInset);
862 0 : DISPLAY_REFLOW_CHANGE();
863 : }
864 0 : else if (aPresContext->IsPaginated()) {
865 : nscoord computedUnpaginatedHeight =
866 : CalcUnpaginagedHeight(aPresContext, (nsTableCellFrame&)*this,
867 0 : *tableFrame, topInset + bottomInset);
868 0 : if (computedUnpaginatedHeight > 0) {
869 0 : const_cast<nsHTMLReflowState&>(aReflowState).SetComputedHeight(computedUnpaginatedHeight);
870 0 : DISPLAY_REFLOW_CHANGE();
871 : }
872 : }
873 : else {
874 0 : SetHasPctOverHeight(false);
875 : }
876 :
877 : nsHTMLReflowState kidReflowState(aPresContext, aReflowState, firstKid,
878 0 : availSize);
879 :
880 : // Don't be a percent height observer if we're in the middle of
881 : // special-height reflow, in case we get an accidental NotifyPercentHeight()
882 : // call (which we shouldn't honor during special-height reflow)
883 0 : if (!aReflowState.mFlags.mSpecialHeightReflow) {
884 : // mPercentHeightObserver is for children of cells in quirks mode,
885 : // but only those than are tables in standards mode. NeedsToObserve
886 : // will determine how far this is propagated to descendants.
887 0 : kidReflowState.mPercentHeightObserver = this;
888 : }
889 : // Don't propagate special height reflow state to our kids
890 0 : kidReflowState.mFlags.mSpecialHeightReflow = false;
891 :
892 0 : if (aReflowState.mFlags.mSpecialHeightReflow ||
893 0 : (GetFirstInFlow()->GetStateBits() & NS_TABLE_CELL_HAD_SPECIAL_REFLOW)) {
894 : // We need to force the kid to have mVResize set if we've had a
895 : // special reflow in the past, since the non-special reflow needs to
896 : // resize back to what it was without the special height reflow.
897 0 : kidReflowState.mFlags.mVResize = true;
898 : }
899 :
900 0 : nsPoint kidOrigin(leftInset, topInset);
901 0 : nsRect origRect = firstKid->GetRect();
902 0 : nsRect origVisualOverflow = firstKid->GetVisualOverflowRect();
903 0 : bool firstReflow = (firstKid->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
904 :
905 : ReflowChild(firstKid, aPresContext, kidSize, kidReflowState,
906 0 : kidOrigin.x, kidOrigin.y, NS_FRAME_INVALIDATE_ON_MOVE, aStatus);
907 0 : if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
908 : // Don't pass OVERFLOW_INCOMPLETE through tables until they can actually handle it
909 : //XXX should paginate overflow as overflow, but not in this patch (bug 379349)
910 0 : NS_FRAME_SET_INCOMPLETE(aStatus);
911 0 : printf("Set table cell incomplete %p\n", static_cast<void*>(this));
912 : }
913 :
914 : // XXXbz is this invalidate actually needed, really?
915 0 : if (GetStateBits() & NS_FRAME_IS_DIRTY) {
916 0 : InvalidateFrameSubtree();
917 : }
918 :
919 : #ifdef NS_DEBUG
920 0 : DebugCheckChildSize(firstKid, kidSize, availSize);
921 : #endif
922 :
923 : // 0 dimensioned cells need to be treated specially in Standard/NavQuirks mode
924 : // see testcase "emptyCells.html"
925 0 : nsIFrame* prevInFlow = GetPrevInFlow();
926 : bool isEmpty;
927 0 : if (prevInFlow) {
928 0 : isEmpty = static_cast<nsTableCellFrame*>(prevInFlow)->GetContentEmpty();
929 : } else {
930 0 : isEmpty = !CellHasVisibleContent(kidSize.height, tableFrame, firstKid);
931 : }
932 0 : SetContentEmpty(isEmpty);
933 :
934 : // Place the child
935 : FinishReflowChild(firstKid, aPresContext, &kidReflowState, kidSize,
936 0 : kidOrigin.x, kidOrigin.y, 0);
937 :
938 : nsTableFrame::InvalidateFrame(firstKid, origRect, origVisualOverflow,
939 0 : firstReflow);
940 :
941 : // first, compute the height which can be set w/o being restricted by aMaxSize.height
942 0 : nscoord cellHeight = kidSize.height;
943 :
944 0 : if (NS_UNCONSTRAINEDSIZE != cellHeight) {
945 0 : cellHeight += topInset + bottomInset;
946 : }
947 :
948 : // next determine the cell's width
949 0 : nscoord cellWidth = kidSize.width; // at this point, we've factored in the cell's style attributes
950 :
951 : // factor in border and padding
952 0 : if (NS_UNCONSTRAINEDSIZE != cellWidth) {
953 0 : cellWidth += leftInset + rightInset;
954 : }
955 :
956 : // set the cell's desired size and max element size
957 0 : aDesiredSize.width = cellWidth;
958 0 : aDesiredSize.height = cellHeight;
959 :
960 : // the overflow area will be computed when the child will be vertically aligned
961 :
962 0 : if (aReflowState.mFlags.mSpecialHeightReflow) {
963 0 : if (aDesiredSize.height > mRect.height) {
964 : // set a bit indicating that the pct height contents exceeded
965 : // the height that they could honor in the pass 2 reflow
966 0 : SetHasPctOverHeight(true);
967 : }
968 0 : if (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) {
969 0 : aDesiredSize.height = mRect.height;
970 : }
971 : }
972 :
973 : // If our parent is in initial reflow, it'll handle invalidating our
974 : // entire overflow rect.
975 0 : if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
976 0 : CheckInvalidateSizeChange(aDesiredSize);
977 : }
978 :
979 : // remember the desired size for this reflow
980 0 : SetDesiredSize(aDesiredSize);
981 :
982 0 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
983 0 : return NS_OK;
984 : }
985 :
986 : /* ----- global methods ----- */
987 :
988 0 : NS_QUERYFRAME_HEAD(nsTableCellFrame)
989 0 : NS_QUERYFRAME_ENTRY(nsTableCellFrame)
990 0 : NS_QUERYFRAME_ENTRY(nsITableCellLayout)
991 0 : NS_QUERYFRAME_ENTRY(nsIPercentHeightObserver)
992 0 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
993 :
994 : #ifdef ACCESSIBILITY
995 : already_AddRefed<nsAccessible>
996 0 : nsTableCellFrame::CreateAccessible()
997 : {
998 0 : nsAccessibilityService* accService = nsIPresShell::AccService();
999 0 : if (accService) {
1000 : return accService->CreateHTMLTableCellAccessible(mContent,
1001 0 : PresContext()->PresShell());
1002 : }
1003 :
1004 0 : return nsnull;
1005 : }
1006 : #endif
1007 :
1008 : /* This is primarily for editor access via nsITableLayout */
1009 : NS_IMETHODIMP
1010 0 : nsTableCellFrame::GetCellIndexes(PRInt32 &aRowIndex, PRInt32 &aColIndex)
1011 : {
1012 0 : nsresult res = GetRowIndex(aRowIndex);
1013 0 : if (NS_FAILED(res))
1014 : {
1015 0 : aColIndex = 0;
1016 0 : return res;
1017 : }
1018 0 : aColIndex = mColIndex;
1019 0 : return NS_OK;
1020 : }
1021 :
1022 : nsIFrame*
1023 0 : NS_NewTableCellFrame(nsIPresShell* aPresShell,
1024 : nsStyleContext* aContext,
1025 : bool aIsBorderCollapse)
1026 : {
1027 0 : if (aIsBorderCollapse)
1028 0 : return new (aPresShell) nsBCTableCellFrame(aContext);
1029 : else
1030 0 : return new (aPresShell) nsTableCellFrame(aContext);
1031 : }
1032 :
1033 0 : NS_IMPL_FRAMEARENA_HELPERS(nsBCTableCellFrame)
1034 :
1035 : nsMargin*
1036 0 : nsTableCellFrame::GetBorderWidth(nsMargin& aBorder) const
1037 : {
1038 0 : aBorder = GetStyleBorder()->GetActualBorder();
1039 0 : return &aBorder;
1040 : }
1041 :
1042 : nsIAtom*
1043 0 : nsTableCellFrame::GetType() const
1044 : {
1045 0 : return nsGkAtoms::tableCellFrame;
1046 : }
1047 :
1048 : #ifdef DEBUG
1049 : NS_IMETHODIMP
1050 0 : nsTableCellFrame::GetFrameName(nsAString& aResult) const
1051 : {
1052 0 : return MakeFrameName(NS_LITERAL_STRING("TableCell"), aResult);
1053 : }
1054 : #endif
1055 :
1056 : // nsBCTableCellFrame
1057 :
1058 0 : nsBCTableCellFrame::nsBCTableCellFrame(nsStyleContext* aContext)
1059 0 : :nsTableCellFrame(aContext)
1060 : {
1061 0 : mTopBorder = mRightBorder = mBottomBorder = mLeftBorder = 0;
1062 0 : }
1063 :
1064 0 : nsBCTableCellFrame::~nsBCTableCellFrame()
1065 : {
1066 0 : }
1067 :
1068 : nsIAtom*
1069 0 : nsBCTableCellFrame::GetType() const
1070 : {
1071 0 : return nsGkAtoms::bcTableCellFrame;
1072 : }
1073 :
1074 : /* virtual */ nsMargin
1075 0 : nsBCTableCellFrame::GetUsedBorder() const
1076 : {
1077 0 : nsMargin result;
1078 0 : GetBorderWidth(result);
1079 : return result;
1080 : }
1081 :
1082 : /* virtual */ bool
1083 0 : nsBCTableCellFrame::GetBorderRadii(nscoord aRadii[8]) const
1084 : {
1085 0 : NS_FOR_CSS_HALF_CORNERS(corner) {
1086 0 : aRadii[corner] = 0;
1087 : }
1088 0 : return false;
1089 : }
1090 :
1091 : #ifdef DEBUG
1092 : NS_IMETHODIMP
1093 0 : nsBCTableCellFrame::GetFrameName(nsAString& aResult) const
1094 : {
1095 0 : return MakeFrameName(NS_LITERAL_STRING("BCTableCell"), aResult);
1096 : }
1097 : #endif
1098 :
1099 : nsMargin*
1100 0 : nsBCTableCellFrame::GetBorderWidth(nsMargin& aBorder) const
1101 : {
1102 0 : PRInt32 aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
1103 0 : aBorder.top = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips, mTopBorder);
1104 0 : aBorder.right = BC_BORDER_LEFT_HALF_COORD(aPixelsToTwips, mRightBorder);
1105 0 : aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips, mBottomBorder);
1106 0 : aBorder.left = BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, mLeftBorder);
1107 0 : return &aBorder;
1108 : }
1109 :
1110 : BCPixelSize
1111 0 : nsBCTableCellFrame::GetBorderWidth(mozilla::css::Side aSide) const
1112 : {
1113 0 : switch(aSide) {
1114 : case NS_SIDE_TOP:
1115 0 : return BC_BORDER_BOTTOM_HALF(mTopBorder);
1116 : case NS_SIDE_RIGHT:
1117 0 : return BC_BORDER_LEFT_HALF(mRightBorder);
1118 : case NS_SIDE_BOTTOM:
1119 0 : return BC_BORDER_TOP_HALF(mBottomBorder);
1120 : default:
1121 0 : return BC_BORDER_RIGHT_HALF(mLeftBorder);
1122 : }
1123 : }
1124 :
1125 : void
1126 0 : nsBCTableCellFrame::SetBorderWidth(mozilla::css::Side aSide,
1127 : BCPixelSize aValue)
1128 : {
1129 0 : switch(aSide) {
1130 : case NS_SIDE_TOP:
1131 0 : mTopBorder = aValue;
1132 0 : break;
1133 : case NS_SIDE_RIGHT:
1134 0 : mRightBorder = aValue;
1135 0 : break;
1136 : case NS_SIDE_BOTTOM:
1137 0 : mBottomBorder = aValue;
1138 0 : break;
1139 : default:
1140 0 : mLeftBorder = aValue;
1141 : }
1142 0 : }
1143 :
1144 : /* virtual */ nsMargin
1145 0 : nsBCTableCellFrame::GetBorderOverflow()
1146 : {
1147 0 : nsMargin halfBorder;
1148 0 : PRInt32 p2t = nsPresContext::AppUnitsPerCSSPixel();
1149 0 : halfBorder.top = BC_BORDER_TOP_HALF_COORD(p2t, mTopBorder);
1150 0 : halfBorder.right = BC_BORDER_RIGHT_HALF_COORD(p2t, mRightBorder);
1151 0 : halfBorder.bottom = BC_BORDER_BOTTOM_HALF_COORD(p2t, mBottomBorder);
1152 0 : halfBorder.left = BC_BORDER_LEFT_HALF_COORD(p2t, mLeftBorder);
1153 : return halfBorder;
1154 : }
1155 :
1156 :
1157 : void
1158 0 : nsBCTableCellFrame::PaintBackground(nsRenderingContext& aRenderingContext,
1159 : const nsRect& aDirtyRect,
1160 : nsPoint aPt,
1161 : PRUint32 aFlags)
1162 : {
1163 : // make border-width reflect the half of the border-collapse
1164 : // assigned border that's inside the cell
1165 0 : nsMargin borderWidth;
1166 0 : GetBorderWidth(borderWidth);
1167 :
1168 0 : nsStyleBorder myBorder(*GetStyleBorder());
1169 : // We're making an ephemeral stack copy here, so just copy this debug-only
1170 : // member to prevent assertions.
1171 : #ifdef DEBUG
1172 0 : myBorder.mImageTracked = GetStyleBorder()->mImageTracked;
1173 : #endif
1174 :
1175 0 : NS_FOR_CSS_SIDES(side) {
1176 0 : myBorder.SetBorderWidth(side, borderWidth.Side(side));
1177 : }
1178 :
1179 0 : nsRect rect(aPt, GetSize());
1180 : // bypassing nsCSSRendering::PaintBackground is safe because this kind
1181 : // of frame cannot be used for the root element
1182 : nsCSSRendering::PaintBackgroundWithSC(PresContext(), aRenderingContext, this,
1183 : aDirtyRect, rect,
1184 : GetStyleContext(), myBorder,
1185 0 : aFlags, nsnull);
1186 :
1187 : #ifdef DEBUG
1188 0 : myBorder.mImageTracked = false;
1189 : #endif
1190 0 : }
|