mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 23:06:52 +00:00
05f03280bb
- Bug 1085783 (Part 1) - Snap both the fill and dest rects using UserToDeviceSnapped() when pixel snapping images. r=roc (97c8ea37a9) - Bug 1085783 (Part 2) - Add a test for rounding behavior when high-quality downscaling. r=roc (2851c696c4) - Bug 1218851. Fix comments related to nsIPresShell::RenderDocument and flags RENDER_DOCUMENT_RELATIVE and RENDER_IGNORE_VIEWPORT_SCROLLING. r=roc (897eb061a2) - Bug 1223255 - Use Animation::AnimationTimeToTimeStamp instead of timeline->ToTimeStamp. r=bbirtles (b05fc6c868) - Bug 1216030 - Part 1: Remove CanAnimate_HasGeometricProperty. r=dbaron (8f8f380828) - Bug 1216030 - Part 2: Remove gfxPlatform::OffMainThreadCompositingEnabled from CanAnimatePropertyOnCompositor. r=dbaron (983f626f3d) - Bug 1216030 - Part 3: Move AreAsyncAnimationsEnabled check outside animation properties loop. r=dbaron (273b21d3a9) - Bug 1216030 - Part 4: Move IsCompositorAnimationDisabledForFrame outside animation properties loop. r=dbaron (4f5ba30f2d) - Bug 1216030 - Part 5: Add KeyframeEffectReadOnly::CanAnimateTransformOnCompositor. r=bbirtles (a87ab8f397) - Bug 1216030 - Part 6: Add KeyframeEffectReadOnly::IsGeometricProperty. r=bbirtles (9dbb1c9fe0) - Bug 1216030 - Part 7: Add nsIFrame::RefusedAsyncAnimation. r=dbaron (9b0582e9e7) - Bug 1216030 - Part 8: Add KeyframeEffectReadOnly::GetAnimationFrame. r=bbirtles (3915b03b48) - Bug 1216030 - Part 9: We don't need to call CanPerformOnCompositorThread in RequestRestyle. (fe46feecdb) - Bug 1216030 - Part 8.5: Animation::CanThrottle() should check that all animation properties are running on compositor. r=bbirtles (dbee36ccc7) - Bug 1216030 - Part 10: Remove CanAnimate_AllowPartial flag. r=bbirtles (eb30ac714f) - Bug 1216030 - Part 11: Add KeyframeEffect::CanAnimatePropertyOnCompositor. r=bbirtles (f71cb641ec) - Bug 1216030 - Part 12: Pass nsIFrame to CanPerformOnCompositorThread to avoid redundant process for getting nsIFrame. r=dbaron (c9dbe043ad) - Bug 1216030 - Part 13: Remove existsProperty check from CanPerformOnCompositorThread. r=dbaron (e3dde151af) - Bug 1216030 - Part 14: Add KeyframeEffectReadOnly::GetPresContext and KeyframeEffectReadonly::GetRenderedDocument. r=bbirtles (7edbf430e9) - Bug 1216030 - Part 15: Add KeyframeEffectReadOnly::GetCollection. r=bbirtles (2652435de5) - Bug 1216030 - Part 16: Move CanThrottleAnimation and CanThrottleTransformChanges from AnimationCollection into KeyframeEffectReadOnly::CanThrottle. r=bbirtles (d890691ebb) - Bug 1216030 - Part 17: Do not calculate unthrottle interval for transform animation every time. r=bbirtles (c7a3767422) - Bug 1216030 - Part 18: Remove IsCurrent() check in assertion in CanThrottle. r=bbirtles (6de694634a) - Bug 1181976 - Rename WillChangeBudgetWarning in dom/dom.properties to reflect string change. r=flod (abc159ebba) - Bug 1191412 - Fix logic and text for the WillChange warning. r=roc (f2900114f1) - Bug 1180899 - Do not clobber frame metrics on the root layer added during a previous paint if there is no other frame metrics for the root scroll frame. r=tn (30f2dcf21b) - Bug 1208673 - Do HitTest with skipping non-leaf preserve-3d transform items. r=roc (a042872d32) - Bug 947062 - Layerize background images with animated background-position if possible. r=mattwoodrow (075dedff4a) - Bug 1172310. Don't add viewport frame bounds to the layer event regions because they are never the result of hit testing. r=roc (1ecdd06c0d) - Bug 1213582. Don't flatten away opacity:0 containers. r=mattwoodrow (d1f9c205e1) - Bug 1213582. Skip display items in ProcessDisplayItems if we only need items for event regions, and this item isn't one and doesn't have descendants. r=mattwoodrow (3511595652) - Bug 1183085 - Correct the name for nsDisplayItem; r=roc (fb1a59294f) - Bug 1183085 - Update description for nsDisplayList methods; r=roc (39eafdb099) - Bug 1216851 - Don't include event regions when deciding if we can flatten opacity. r=roc (fc518688a4) - Bug 1215412 - Apply perspective origin after transform origin. r=jwatt (a30f0351a3) - Bug 1152263 - Ensure Matrix4x4::ProjectRectBounds being functional for Rect with zero width/height. r=mattwoodrow (5ca3086e04) - Bug 1217012 - Use doubles when untransforming points since we need the extra precision. r=kip (81acd626e8) - Bug 1042536 - Allow ImageLayer optimization to be used for some clipped background images. r=mstange (b9b89b2d25) - Bug 1221677 - "[css-grid] Put the 'subgrid' support behind a pref, disabled by default". r=mats (400e9d865a) - Bug 1150042 - Make nsLayoutUtils::DrawSingleUnscaledImage use CSSIntSize instead of unitless nsIntSize. r=dholbert (393062cd87) - Bug 1173305 - Convert BasicTableLayoutStrategy to work with logical coordinates. r=dholbert (e133cad49a) - namespace comment (6fc3ad3f4a) - Bug 1220621. When removing a <col>, only create an anonymous colframe to replace it if one is really needed. r=dbaron (e29d8a7248) - Bug 1178250 - Don't call ConsiderChildOverflow until the child has been placed in the right location when reflowing a vertical-rl table. r=dholbert (1327793032) - Bug 1186998 - Align overflowing table-cell content to content-box. r=dholbert (d2356a20c0) - Bug 1213465 - Combine DrawResults correctly in nsTablePainter. r=tn (61e725a4ad) - minor (0df6057957) - bits of Bug 1163227: Part5 (6a99380110) - minor (59f78b2265) - Bug 1206982 - getUserMedia s/PermissionDeniedError/SecurityError/. r=jesup (782b3536a2) - Bug 1218799: Shutdown MediaManager engines from the MediaManager thread r=jib (351bba0486) - Bug 1186708 - Fix debug-only assert (crash) on advanced browserWindow constraint. r=jesup (86fcfa999d) - Bug 1170958 - Remove ProcessedMediaStream::ForwardTrackEnabled. r=roc,jesup (4663d7a46c) - missing bit of Bug 110540 (47b80e731f) - missing bit of Bug 1113032 - Replace deprecated expression closures in about:newtab (d1643b5cbc) - Bug 980014 - Allow new tab grid layout to reduce rows/columns if the window can't fit 3x3 [r=adw] (55b60edfc2) - Bug 991210 - [new tab page] Tiles are sometimes arranged all in a single line (wrapping as appropriate, e.g. to two lines with 5 items and then 4 items), instead of 3x3 grid [r=adw] (876170c921) - Bug 1070620 - Render newtab page grid and sites in a single step using a DocumentFragment r=gijs,adw (eb47e89544) - Bit of 1126188 (c3e9a85e9b) - Bug 1223916 - Prohibit direct method calls at the parser level in self-hosted code. (r=till) (1489fbb2f3) - Bug 1219057 - Do not show "Unable to print stack trace" for exception thrown while compiling top-level script. r=jandem (df74029ee8) - Bug 1186973 - Evaluate assertEqBytecode: Print length as numbers. r=h4writer (57f9e68d53) - Bug 1218636 - IonMonkey: MIPS64: Add support into shell. r=lth (dc4de53cf5) - Bug 1192329 - Change JS shell to default to the standard version of JS (not 1.7+) 1/2; r=jorendorff (e40087f5b8) - Bug 1192329 - Change JS shell to default to the standard version of JS (not 1.7+) 2/2; r=jorendorff (4d74d1f639) - Bug 1192329 - Fix broken asm tests by explicitly setting js version; r=jorendorff (adf502c8db) - Bug 1108603 - Evaluate ensure that the global is configured such that we can always clone singletons. r=jonco (8a888042dd) - Bug 1184393 - Rename some js shell test variables for better readability; r=sfink (06e2293f34) - Bug 1213104 - Pass the ProgressBar directly, since we are no longer using results; r=sfink (16b4af8c3e) - Bug 1212756 - Fix jstests --debug option r=terrence (89caa65dc5) - Bug 1213365 - Share environment control code between js and jit test harnesses; r=sfink (274c4f2d2e) - Bug 1206987 - Only disable the GPF dialog during testing; r=sfink (a507b1b591) - Bug 1212349 - Encapsulate the shell's per-runtime state r=jandem (4ec884973d) - Bug 1215063 - Implement a simple module loader for the shell r=shu r=froydnj (a916f0ee03) - Bug 1214051 - Reject NaN as a sampling probability, and test the floating point value range harder. r=jimb (842e822471) - Bug 1225176 - Don't call wrap() in JitActivation constructor, it can GC and crash. r=fitzgen (d989a2b157) - Bug 1218643 - remove support for deprecated asm.js heap length. r=luke (6ad156f10d) - Bug 1224280 - Fix asm.js console warning when disabled by debugger and parsing off-thread. r=luke (7bf76d0a1f) - Bug 1221660 - Part 1: Stop populating ParseNode::pn_offset most of the time. r=Waldo. (24d013fe30) - Bug 1221660 - Part 2: Move pn_offset into a branch of the ParseNode::pn_u union. Add a subclass of ParseNode for PNK_CASE nodes. Merge PNK_DEFAULT with PNK_CASE. r=Waldo. (12514bc644) - Bug 1200609 - Odin: Update comments and code mentioning interrupting via mprotect (r=benj) (a60ec9d0d0) - Bug 1218644 - OdinMonkey: MIPS64: Add support for Loongson3. r=lth (57a1865d1d) - Bug 1225392 part 1. Expose JSAPI for getting %IteratorPrototype%. r=efaust (816e68dddd) - Bug 1225392 part 2. WebIDL autogenerated iterators should chain up to %IteratorPrototype%. r=qdot (834fc71f90) - No bug. Reword a comment slightly because it confused me. r=woof!, DONTBUILD (c2c41d535a) - Bug 1147752 - Keep typedefs consistent. r=jgilbert (605d63c0e4) - Bug 1207672 - Add support for APPLE_framebuffer_multisample r=snorp (0f4ef4420d) - Bug 1207205 - Remove fGetActiveUniformName. r=jrmuizel (9d1c97f194) - Bug 1208513 - Add support for GL_APPLE_sync r=jgilbert (6d70401d89) - Bug 1222175 - initialize base of ScaledFontDWrite before its members; r=Bas (120c5fa334) - Bug 1217941 - remove <iomanip> from ScaleFactors2D.h; r=jrmuizel (e5a08d95e2) - Bug 1222569 - fix initialization order in SourceSurfaceD2D1; r=Bas (484084f551) - Bug 1208661 - Implement SourceSurfaceDual::GetDataSurface() for debugging purposes. r=BenWa (de255f344a) - Bug 1185011: Add 'override' annotations to DataSourceSurface subclasses in SourceSurfaceRawData.h, to fix clang -Winconsistent-missing-override build warnings/errors. rs=ehsan (dc3ff4fa07) - Bug 1222298 - GFX: 2D: Make convolverLS3 more like upstream. r=seth (06e555709d) - Bug 1157065- GFX: 2D: Implement AlphaBoxBlur in LS3 MMI. r=jrmuizel (ca818df231) - Bug 1220673 - Make DrawTargetCG::Mask() MOZ_CRASH (a649db3d99) - Bug 1221616: Use ID2D1CommandList instead of a bitmap for temporary D2D drawing. r=jrmuizel (9785977521) - Bug 1220624: Make MaskSurface properly take into account the possibilities of partial uploads. r=jrmuizel (9dd3d65880) - Bug 1222569 - remove unused variable from DrawTargetD2D1.cpp; r=Bas (e6c5aa717b)
1076 lines
44 KiB
C++
1076 lines
44 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
// vim:cindent:ts=4:et:sw=4:
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/*
|
|
* Web-compatible algorithms that determine column and table widths,
|
|
* used for CSS2's 'table-layout: auto'.
|
|
*/
|
|
|
|
#include "BasicTableLayoutStrategy.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include "nsTableFrame.h"
|
|
#include "nsTableColFrame.h"
|
|
#include "nsTableCellFrame.h"
|
|
#include "nsLayoutUtils.h"
|
|
#include "nsGkAtoms.h"
|
|
#include "SpanningCellSorter.h"
|
|
#include "nsIContent.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::layout;
|
|
|
|
namespace css = mozilla::css;
|
|
|
|
#undef DEBUG_TABLE_STRATEGY
|
|
|
|
BasicTableLayoutStrategy::BasicTableLayoutStrategy(nsTableFrame *aTableFrame)
|
|
: nsITableLayoutStrategy(nsITableLayoutStrategy::Auto)
|
|
, mTableFrame(aTableFrame)
|
|
{
|
|
MarkIntrinsicISizesDirty();
|
|
}
|
|
|
|
/* virtual */
|
|
BasicTableLayoutStrategy::~BasicTableLayoutStrategy()
|
|
{
|
|
}
|
|
|
|
/* virtual */ nscoord
|
|
BasicTableLayoutStrategy::GetMinISize(nsRenderingContext* aRenderingContext)
|
|
{
|
|
DISPLAY_MIN_WIDTH(mTableFrame, mMinISize);
|
|
if (mMinISize == NS_INTRINSIC_WIDTH_UNKNOWN) {
|
|
ComputeIntrinsicISizes(aRenderingContext);
|
|
}
|
|
return mMinISize;
|
|
}
|
|
|
|
/* virtual */ nscoord
|
|
BasicTableLayoutStrategy::GetPrefISize(nsRenderingContext* aRenderingContext,
|
|
bool aComputingSize)
|
|
{
|
|
DISPLAY_PREF_WIDTH(mTableFrame, mPrefISize);
|
|
NS_ASSERTION((mPrefISize == NS_INTRINSIC_WIDTH_UNKNOWN) ==
|
|
(mPrefISizePctExpand == NS_INTRINSIC_WIDTH_UNKNOWN),
|
|
"dirtyness out of sync");
|
|
if (mPrefISize == NS_INTRINSIC_WIDTH_UNKNOWN) {
|
|
ComputeIntrinsicISizes(aRenderingContext);
|
|
}
|
|
return aComputingSize ? mPrefISizePctExpand : mPrefISize;
|
|
}
|
|
|
|
struct CellISizeInfo {
|
|
CellISizeInfo(nscoord aMinCoord, nscoord aPrefCoord,
|
|
float aPrefPercent, bool aHasSpecifiedISize)
|
|
: hasSpecifiedISize(aHasSpecifiedISize)
|
|
, minCoord(aMinCoord)
|
|
, prefCoord(aPrefCoord)
|
|
, prefPercent(aPrefPercent)
|
|
{
|
|
}
|
|
|
|
bool hasSpecifiedISize;
|
|
nscoord minCoord;
|
|
nscoord prefCoord;
|
|
float prefPercent;
|
|
};
|
|
|
|
// Used for both column and cell calculations. The parts needed only
|
|
// for cells are skipped when aIsCell is false.
|
|
static CellISizeInfo
|
|
GetISizeInfo(nsRenderingContext *aRenderingContext,
|
|
nsIFrame *aFrame, WritingMode aWM, bool aIsCell)
|
|
{
|
|
nscoord minCoord, prefCoord;
|
|
const nsStylePosition *stylePos = aFrame->StylePosition();
|
|
bool isQuirks = aFrame->PresContext()->CompatibilityMode() ==
|
|
eCompatibility_NavQuirks;
|
|
nscoord boxSizingToBorderEdge = 0;
|
|
if (aIsCell) {
|
|
// If aFrame is a container for font size inflation, then shrink
|
|
// wrapping inside of it should not apply font size inflation.
|
|
AutoMaybeDisableFontInflation an(aFrame);
|
|
|
|
minCoord = aFrame->GetMinISize(aRenderingContext);
|
|
prefCoord = aFrame->GetPrefISize(aRenderingContext);
|
|
// Until almost the end of this function, minCoord and prefCoord
|
|
// represent the box-sizing based isize values (which mean they
|
|
// should include inline padding and border width when
|
|
// box-sizing is set to border-box).
|
|
// Note that this function returns border-box isize, we add the
|
|
// outer edges near the end of this function.
|
|
|
|
// XXX Should we ignore percentage padding?
|
|
nsIFrame::IntrinsicISizeOffsetData offsets =
|
|
aFrame->IntrinsicISizeOffsets();
|
|
|
|
// In quirks mode, table cell isize should be content-box,
|
|
// but bsize should be border box.
|
|
// Because of this historic anomaly, we do not use quirk.css.
|
|
// (We can't specify one value of box-sizing for isize and another
|
|
// for bsize).
|
|
// For this reason, we also do not use box-sizing for just one of
|
|
// them, as this may be confusing.
|
|
if (isQuirks) {
|
|
boxSizingToBorderEdge = offsets.hPadding + offsets.hBorder;
|
|
}
|
|
else {
|
|
switch (stylePos->mBoxSizing) {
|
|
case NS_STYLE_BOX_SIZING_CONTENT:
|
|
boxSizingToBorderEdge = offsets.hPadding + offsets.hBorder;
|
|
break;
|
|
case NS_STYLE_BOX_SIZING_PADDING:
|
|
minCoord += offsets.hPadding;
|
|
prefCoord += offsets.hPadding;
|
|
boxSizingToBorderEdge = offsets.hBorder;
|
|
break;
|
|
default:
|
|
// NS_STYLE_BOX_SIZING_BORDER
|
|
minCoord += offsets.hPadding + offsets.hBorder;
|
|
prefCoord += offsets.hPadding + offsets.hBorder;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
minCoord = 0;
|
|
prefCoord = 0;
|
|
}
|
|
float prefPercent = 0.0f;
|
|
bool hasSpecifiedISize = false;
|
|
|
|
const nsStyleCoord& iSize = stylePos->ISize(aWM);
|
|
nsStyleUnit unit = iSize.GetUnit();
|
|
// NOTE: We're ignoring calc() units with percentages here, for lack of a
|
|
// sensible idea for what to do with them. This means calc() with
|
|
// percentages is basically handled like 'auto' for table cells and
|
|
// columns.
|
|
if (iSize.ConvertsToLength()) {
|
|
hasSpecifiedISize = true;
|
|
// Note: since ComputeISizeValue was designed to return content-box
|
|
// isize, it will (in some cases) subtract the box-sizing edges.
|
|
// We prevent this unwanted behavior by calling it with
|
|
// aContentEdgeToBoxSizing and aBoxSizingToMarginEdge set to 0.
|
|
nscoord c = nsLayoutUtils::ComputeISizeValue(aRenderingContext,
|
|
aFrame, 0, 0, 0, iSize);
|
|
// Quirk: A cell with "nowrap" set and a coord value for the
|
|
// isize which is bigger than the intrinsic minimum isize uses
|
|
// that coord value as the minimum isize.
|
|
// This is kept up-to-date with dynamic changes to nowrap by code in
|
|
// nsTableCellFrame::AttributeChanged
|
|
if (aIsCell && c > minCoord && isQuirks &&
|
|
aFrame->GetContent()->HasAttr(kNameSpaceID_None,
|
|
nsGkAtoms::nowrap)) {
|
|
minCoord = c;
|
|
}
|
|
prefCoord = std::max(c, minCoord);
|
|
} else if (unit == eStyleUnit_Percent) {
|
|
prefPercent = iSize.GetPercentValue();
|
|
} else if (unit == eStyleUnit_Enumerated && aIsCell) {
|
|
switch (iSize.GetIntValue()) {
|
|
case NS_STYLE_WIDTH_MAX_CONTENT:
|
|
// 'inline-size' only affects pref isize, not min
|
|
// isize, so don't change anything
|
|
break;
|
|
case NS_STYLE_WIDTH_MIN_CONTENT:
|
|
prefCoord = minCoord;
|
|
break;
|
|
case NS_STYLE_WIDTH_FIT_CONTENT:
|
|
case NS_STYLE_WIDTH_AVAILABLE:
|
|
// act just like 'inline-size: auto'
|
|
break;
|
|
default:
|
|
NS_NOTREACHED("unexpected enumerated value");
|
|
}
|
|
}
|
|
|
|
nsStyleCoord maxISize(stylePos->MaxISize(aWM));
|
|
if (maxISize.GetUnit() == eStyleUnit_Enumerated) {
|
|
if (!aIsCell || maxISize.GetIntValue() == NS_STYLE_WIDTH_AVAILABLE) {
|
|
maxISize.SetNoneValue();
|
|
} else if (maxISize.GetIntValue() == NS_STYLE_WIDTH_FIT_CONTENT) {
|
|
// for 'max-inline-size', '-moz-fit-content' is like
|
|
// '-moz-max-content'
|
|
maxISize.SetIntValue(NS_STYLE_WIDTH_MAX_CONTENT,
|
|
eStyleUnit_Enumerated);
|
|
}
|
|
}
|
|
unit = maxISize.GetUnit();
|
|
// XXX To really implement 'max-inline-size' well, we'd need to store
|
|
// it separately on the columns.
|
|
if (maxISize.ConvertsToLength() || unit == eStyleUnit_Enumerated) {
|
|
nscoord c =
|
|
nsLayoutUtils::ComputeISizeValue(aRenderingContext, aFrame,
|
|
0, 0, 0, maxISize);
|
|
minCoord = std::min(c, minCoord);
|
|
prefCoord = std::min(c, prefCoord);
|
|
} else if (unit == eStyleUnit_Percent) {
|
|
float p = stylePos->MaxISize(aWM).GetPercentValue();
|
|
if (p < prefPercent) {
|
|
prefPercent = p;
|
|
}
|
|
}
|
|
// treat calc() with percentages on max-inline-size just like 'none'.
|
|
|
|
nsStyleCoord minISize(stylePos->MinISize(aWM));
|
|
if (minISize.GetUnit() == eStyleUnit_Enumerated) {
|
|
if (!aIsCell || minISize.GetIntValue() == NS_STYLE_WIDTH_AVAILABLE) {
|
|
minISize.SetCoordValue(0);
|
|
} else if (minISize.GetIntValue() == NS_STYLE_WIDTH_FIT_CONTENT) {
|
|
// for 'min-inline-size', '-moz-fit-content' is like
|
|
// '-moz-min-content'
|
|
minISize.SetIntValue(NS_STYLE_WIDTH_MIN_CONTENT,
|
|
eStyleUnit_Enumerated);
|
|
}
|
|
}
|
|
unit = minISize.GetUnit();
|
|
if (minISize.ConvertsToLength() || unit == eStyleUnit_Enumerated) {
|
|
nscoord c =
|
|
nsLayoutUtils::ComputeISizeValue(aRenderingContext, aFrame,
|
|
0, 0, 0, minISize);
|
|
minCoord = std::max(c, minCoord);
|
|
prefCoord = std::max(c, prefCoord);
|
|
} else if (unit == eStyleUnit_Percent) {
|
|
float p = stylePos->MinISize(aWM).GetPercentValue();
|
|
if (p > prefPercent) {
|
|
prefPercent = p;
|
|
}
|
|
}
|
|
// treat calc() with percentages on min-inline-size just like '0'.
|
|
|
|
// XXX Should col frame have border/padding considered?
|
|
if (aIsCell) {
|
|
minCoord += boxSizingToBorderEdge;
|
|
prefCoord = NSCoordSaturatingAdd(prefCoord, boxSizingToBorderEdge);
|
|
}
|
|
|
|
return CellISizeInfo(minCoord, prefCoord, prefPercent, hasSpecifiedISize);
|
|
}
|
|
|
|
static inline CellISizeInfo
|
|
GetCellISizeInfo(nsRenderingContext *aRenderingContext,
|
|
nsTableCellFrame *aCellFrame, WritingMode aWM)
|
|
{
|
|
return GetISizeInfo(aRenderingContext, aCellFrame, aWM, true);
|
|
}
|
|
|
|
static inline CellISizeInfo
|
|
GetColISizeInfo(nsRenderingContext *aRenderingContext,
|
|
nsIFrame *aFrame, WritingMode aWM)
|
|
{
|
|
return GetISizeInfo(aRenderingContext, aFrame, aWM, false);
|
|
}
|
|
|
|
|
|
/**
|
|
* The algorithm in this function, in addition to meeting the
|
|
* requirements of Web-compatibility, is also invariant under reordering
|
|
* of the rows within a table (something that most, but not all, other
|
|
* browsers are).
|
|
*/
|
|
void
|
|
BasicTableLayoutStrategy::ComputeColumnIntrinsicISizes(nsRenderingContext* aRenderingContext)
|
|
{
|
|
nsTableFrame *tableFrame = mTableFrame;
|
|
nsTableCellMap *cellMap = tableFrame->GetCellMap();
|
|
WritingMode wm = tableFrame->GetWritingMode();
|
|
|
|
mozilla::AutoStackArena arena;
|
|
SpanningCellSorter spanningCells;
|
|
|
|
// Loop over the columns to consider the columns and cells *without*
|
|
// a colspan.
|
|
int32_t col, col_end;
|
|
for (col = 0, col_end = cellMap->GetColCount(); col < col_end; ++col) {
|
|
nsTableColFrame *colFrame = tableFrame->GetColFrame(col);
|
|
if (!colFrame) {
|
|
NS_ERROR("column frames out of sync with cell map");
|
|
continue;
|
|
}
|
|
colFrame->ResetIntrinsics();
|
|
colFrame->ResetSpanIntrinsics();
|
|
|
|
// Consider the isizes on the column.
|
|
CellISizeInfo colInfo = GetColISizeInfo(aRenderingContext,
|
|
colFrame, wm);
|
|
colFrame->AddCoords(colInfo.minCoord, colInfo.prefCoord,
|
|
colInfo.hasSpecifiedISize);
|
|
colFrame->AddPrefPercent(colInfo.prefPercent);
|
|
|
|
// Consider the isizes on the column-group. Note that we follow
|
|
// what the HTML spec says here, and make the isize apply to
|
|
// each column in the group, not the group as a whole.
|
|
|
|
// If column has isize, column-group doesn't override isize.
|
|
if (colInfo.minCoord == 0 && colInfo.prefCoord == 0 &&
|
|
colInfo.prefPercent == 0.0f) {
|
|
NS_ASSERTION(colFrame->GetParent()->GetType() ==
|
|
nsGkAtoms::tableColGroupFrame,
|
|
"expected a column-group");
|
|
colInfo = GetColISizeInfo(aRenderingContext,
|
|
colFrame->GetParent(), wm);
|
|
colFrame->AddCoords(colInfo.minCoord, colInfo.prefCoord,
|
|
colInfo.hasSpecifiedISize);
|
|
colFrame->AddPrefPercent(colInfo.prefPercent);
|
|
}
|
|
|
|
// Consider the contents of and the isizes on the cells without
|
|
// colspans.
|
|
nsCellMapColumnIterator columnIter(cellMap, col);
|
|
int32_t row, colSpan;
|
|
nsTableCellFrame* cellFrame;
|
|
while ((cellFrame = columnIter.GetNextFrame(&row, &colSpan))) {
|
|
if (colSpan > 1) {
|
|
spanningCells.AddCell(colSpan, row, col);
|
|
continue;
|
|
}
|
|
|
|
CellISizeInfo info = GetCellISizeInfo(aRenderingContext,
|
|
cellFrame, wm);
|
|
|
|
colFrame->AddCoords(info.minCoord, info.prefCoord,
|
|
info.hasSpecifiedISize);
|
|
colFrame->AddPrefPercent(info.prefPercent);
|
|
}
|
|
#ifdef DEBUG_dbaron_off
|
|
printf("table %p col %d nonspan: min=%d pref=%d spec=%d pct=%f\n",
|
|
mTableFrame, col, colFrame->GetMinCoord(),
|
|
colFrame->GetPrefCoord(), colFrame->GetHasSpecifiedCoord(),
|
|
colFrame->GetPrefPercent());
|
|
#endif
|
|
}
|
|
#ifdef DEBUG_TABLE_STRATEGY
|
|
printf("ComputeColumnIntrinsicISizes single\n");
|
|
mTableFrame->Dump(false, true, false);
|
|
#endif
|
|
|
|
// Consider the cells with a colspan that we saved in the loop above
|
|
// into the spanning cell sorter. We consider these cells by seeing
|
|
// if they require adding to the isizes resulting only from cells
|
|
// with a smaller colspan, and therefore we must process them sorted
|
|
// in increasing order by colspan. For each colspan group, we
|
|
// accumulate new values to accumulate in the column frame's Span*
|
|
// members.
|
|
//
|
|
// Considering things only relative to the isizes resulting from
|
|
// cells with smaller colspans (rather than incrementally including
|
|
// the results from spanning cells, or doing spanning and
|
|
// non-spanning cells in a single pass) means that layout remains
|
|
// row-order-invariant and (except for percentage isizes that add to
|
|
// more than 100%) column-order invariant.
|
|
//
|
|
// Starting with smaller colspans makes it more likely that we
|
|
// satisfy all the constraints given and don't distribute space to
|
|
// columns where we don't need it.
|
|
SpanningCellSorter::Item *item;
|
|
int32_t colSpan;
|
|
while ((item = spanningCells.GetNext(&colSpan))) {
|
|
NS_ASSERTION(colSpan > 1,
|
|
"cell should not have been put in spanning cell sorter");
|
|
do {
|
|
int32_t row = item->row;
|
|
col = item->col;
|
|
CellData *cellData = cellMap->GetDataAt(row, col);
|
|
NS_ASSERTION(cellData && cellData->IsOrig(),
|
|
"bogus result from spanning cell sorter");
|
|
|
|
nsTableCellFrame *cellFrame = cellData->GetCellFrame();
|
|
NS_ASSERTION(cellFrame, "bogus result from spanning cell sorter");
|
|
|
|
CellISizeInfo info =
|
|
GetCellISizeInfo(aRenderingContext, cellFrame, wm);
|
|
|
|
if (info.prefPercent > 0.0f) {
|
|
DistributePctISizeToColumns(info.prefPercent,
|
|
col, colSpan);
|
|
}
|
|
DistributeISizeToColumns(info.minCoord, col, colSpan,
|
|
BTLS_MIN_ISIZE, info.hasSpecifiedISize);
|
|
DistributeISizeToColumns(info.prefCoord, col, colSpan,
|
|
BTLS_PREF_ISIZE, info.hasSpecifiedISize);
|
|
} while ((item = item->next));
|
|
|
|
// Combine the results of the span analysis into the main results,
|
|
// for each increment of colspan.
|
|
|
|
for (col = 0, col_end = cellMap->GetColCount(); col < col_end; ++col) {
|
|
nsTableColFrame *colFrame = tableFrame->GetColFrame(col);
|
|
if (!colFrame) {
|
|
NS_ERROR("column frames out of sync with cell map");
|
|
continue;
|
|
}
|
|
|
|
colFrame->AccumulateSpanIntrinsics();
|
|
colFrame->ResetSpanIntrinsics();
|
|
|
|
#ifdef DEBUG_dbaron_off
|
|
printf("table %p col %d span %d: min=%d pref=%d spec=%d pct=%f\n",
|
|
mTableFrame, col, colSpan, colFrame->GetMinCoord(),
|
|
colFrame->GetPrefCoord(), colFrame->GetHasSpecifiedCoord(),
|
|
colFrame->GetPrefPercent());
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// Prevent percentages from adding to more than 100% by (to be
|
|
// compatible with other browsers) treating any percentages that would
|
|
// increase the total percentage to more than 100% as the number that
|
|
// would increase it to only 100% (which is 0% if we've already hit
|
|
// 100%). This means layout depends on the order of columns.
|
|
float pct_used = 0.0f;
|
|
for (col = 0, col_end = cellMap->GetColCount(); col < col_end; ++col) {
|
|
nsTableColFrame *colFrame = tableFrame->GetColFrame(col);
|
|
if (!colFrame) {
|
|
NS_ERROR("column frames out of sync with cell map");
|
|
continue;
|
|
}
|
|
|
|
colFrame->AdjustPrefPercent(&pct_used);
|
|
}
|
|
|
|
#ifdef DEBUG_TABLE_STRATEGY
|
|
printf("ComputeColumnIntrinsicISizes spanning\n");
|
|
mTableFrame->Dump(false, true, false);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
BasicTableLayoutStrategy::ComputeIntrinsicISizes(nsRenderingContext* aRenderingContext)
|
|
{
|
|
ComputeColumnIntrinsicISizes(aRenderingContext);
|
|
|
|
nsTableCellMap *cellMap = mTableFrame->GetCellMap();
|
|
nscoord min = 0, pref = 0, max_small_pct_pref = 0, nonpct_pref_total = 0;
|
|
float pct_total = 0.0f; // always from 0.0f - 1.0f
|
|
int32_t colCount = cellMap->GetColCount();
|
|
// add a total of (colcount + 1) lots of cellSpacingX for columns where a
|
|
// cell originates
|
|
nscoord add = mTableFrame->GetColSpacing(colCount);
|
|
|
|
for (int32_t col = 0; col < colCount; ++col) {
|
|
nsTableColFrame *colFrame = mTableFrame->GetColFrame(col);
|
|
if (!colFrame) {
|
|
NS_ERROR("column frames out of sync with cell map");
|
|
continue;
|
|
}
|
|
if (mTableFrame->ColumnHasCellSpacingBefore(col)) {
|
|
add += mTableFrame->GetColSpacing(col - 1);
|
|
}
|
|
min += colFrame->GetMinCoord();
|
|
pref = NSCoordSaturatingAdd(pref, colFrame->GetPrefCoord());
|
|
|
|
// Percentages are of the table, so we have to reverse them for
|
|
// intrinsic isizes.
|
|
float p = colFrame->GetPrefPercent();
|
|
if (p > 0.0f) {
|
|
nscoord colPref = colFrame->GetPrefCoord();
|
|
nscoord new_small_pct_expand =
|
|
(colPref == nscoord_MAX ?
|
|
nscoord_MAX : nscoord(float(colPref) / p));
|
|
if (new_small_pct_expand > max_small_pct_pref) {
|
|
max_small_pct_pref = new_small_pct_expand;
|
|
}
|
|
pct_total += p;
|
|
} else {
|
|
nonpct_pref_total = NSCoordSaturatingAdd(nonpct_pref_total,
|
|
colFrame->GetPrefCoord());
|
|
}
|
|
}
|
|
|
|
nscoord pref_pct_expand = pref;
|
|
|
|
// Account for small percentages expanding the preferred isize of
|
|
// *other* columns.
|
|
if (max_small_pct_pref > pref_pct_expand) {
|
|
pref_pct_expand = max_small_pct_pref;
|
|
}
|
|
|
|
// Account for large percentages expanding the preferred isize of
|
|
// themselves. There's no need to iterate over the columns multiple
|
|
// times, since when there is such a need, the small percentage
|
|
// effect is bigger anyway. (I think!)
|
|
NS_ASSERTION(0.0f <= pct_total && pct_total <= 1.0f,
|
|
"column percentage inline-sizes not adjusted down to 100%");
|
|
if (pct_total == 1.0f) {
|
|
if (nonpct_pref_total > 0) {
|
|
pref_pct_expand = nscoord_MAX;
|
|
// XXX Or should I use some smaller value? (Test this using
|
|
// nested tables!)
|
|
}
|
|
} else {
|
|
nscoord large_pct_pref =
|
|
(nonpct_pref_total == nscoord_MAX ?
|
|
nscoord_MAX :
|
|
nscoord(float(nonpct_pref_total) / (1.0f - pct_total)));
|
|
if (large_pct_pref > pref_pct_expand)
|
|
pref_pct_expand = large_pct_pref;
|
|
}
|
|
|
|
// border-spacing isn't part of the basis for percentages
|
|
if (colCount > 0) {
|
|
min += add;
|
|
pref = NSCoordSaturatingAdd(pref, add);
|
|
pref_pct_expand = NSCoordSaturatingAdd(pref_pct_expand, add);
|
|
}
|
|
|
|
mMinISize = min;
|
|
mPrefISize = pref;
|
|
mPrefISizePctExpand = pref_pct_expand;
|
|
}
|
|
|
|
/* virtual */ void
|
|
BasicTableLayoutStrategy::MarkIntrinsicISizesDirty()
|
|
{
|
|
mMinISize = NS_INTRINSIC_WIDTH_UNKNOWN;
|
|
mPrefISize = NS_INTRINSIC_WIDTH_UNKNOWN;
|
|
mPrefISizePctExpand = NS_INTRINSIC_WIDTH_UNKNOWN;
|
|
mLastCalcISize = nscoord_MIN;
|
|
}
|
|
|
|
/* virtual */ void
|
|
BasicTableLayoutStrategy::ComputeColumnISizes(const nsHTMLReflowState& aReflowState)
|
|
{
|
|
nscoord iSize = aReflowState.ComputedISize();
|
|
|
|
if (mLastCalcISize == iSize) {
|
|
return;
|
|
}
|
|
mLastCalcISize = iSize;
|
|
|
|
NS_ASSERTION((mMinISize == NS_INTRINSIC_WIDTH_UNKNOWN) ==
|
|
(mPrefISize == NS_INTRINSIC_WIDTH_UNKNOWN),
|
|
"dirtyness out of sync");
|
|
NS_ASSERTION((mMinISize == NS_INTRINSIC_WIDTH_UNKNOWN) ==
|
|
(mPrefISizePctExpand == NS_INTRINSIC_WIDTH_UNKNOWN),
|
|
"dirtyness out of sync");
|
|
// XXX Is this needed?
|
|
if (mMinISize == NS_INTRINSIC_WIDTH_UNKNOWN) {
|
|
ComputeIntrinsicISizes(aReflowState.rendContext);
|
|
}
|
|
|
|
nsTableCellMap *cellMap = mTableFrame->GetCellMap();
|
|
int32_t colCount = cellMap->GetColCount();
|
|
if (colCount <= 0)
|
|
return; // nothing to do
|
|
|
|
DistributeISizeToColumns(iSize, 0, colCount, BTLS_FINAL_ISIZE, false);
|
|
|
|
#ifdef DEBUG_TABLE_STRATEGY
|
|
printf("ComputeColumnISizes final\n");
|
|
mTableFrame->Dump(false, true, false);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
BasicTableLayoutStrategy::DistributePctISizeToColumns(float aSpanPrefPct,
|
|
int32_t aFirstCol,
|
|
int32_t aColCount)
|
|
{
|
|
// First loop to determine:
|
|
int32_t nonPctColCount = 0; // number of spanned columns without % isize
|
|
nscoord nonPctTotalPrefISize = 0; // total pref isize of those columns
|
|
// and to reduce aSpanPrefPct by columns that already have % isize
|
|
|
|
int32_t scol, scol_end;
|
|
nsTableCellMap *cellMap = mTableFrame->GetCellMap();
|
|
for (scol = aFirstCol, scol_end = aFirstCol + aColCount;
|
|
scol < scol_end; ++scol) {
|
|
nsTableColFrame *scolFrame = mTableFrame->GetColFrame(scol);
|
|
if (!scolFrame) {
|
|
NS_ERROR("column frames out of sync with cell map");
|
|
continue;
|
|
}
|
|
float scolPct = scolFrame->GetPrefPercent();
|
|
if (scolPct == 0.0f) {
|
|
nonPctTotalPrefISize += scolFrame->GetPrefCoord();
|
|
if (cellMap->GetNumCellsOriginatingInCol(scol) > 0) {
|
|
++nonPctColCount;
|
|
}
|
|
} else {
|
|
aSpanPrefPct -= scolPct;
|
|
}
|
|
}
|
|
|
|
if (aSpanPrefPct <= 0.0f || nonPctColCount == 0) {
|
|
// There's no %-isize on the colspan left over to distribute,
|
|
// or there are no columns to which we could distribute %-isize
|
|
return;
|
|
}
|
|
|
|
// Second loop, to distribute what remains of aSpanPrefPct
|
|
// between the non-percent-isize spanned columns
|
|
const bool spanHasNonPctPref = nonPctTotalPrefISize > 0; // Loop invariant
|
|
for (scol = aFirstCol, scol_end = aFirstCol + aColCount;
|
|
scol < scol_end; ++scol) {
|
|
nsTableColFrame *scolFrame = mTableFrame->GetColFrame(scol);
|
|
if (!scolFrame) {
|
|
NS_ERROR("column frames out of sync with cell map");
|
|
continue;
|
|
}
|
|
|
|
if (scolFrame->GetPrefPercent() == 0.0f) {
|
|
NS_ASSERTION((!spanHasNonPctPref ||
|
|
nonPctTotalPrefISize != 0) &&
|
|
nonPctColCount != 0,
|
|
"should not be zero if we haven't allocated "
|
|
"all pref percent");
|
|
|
|
float allocatedPct; // % isize to be given to this column
|
|
if (spanHasNonPctPref) {
|
|
// Group so we're multiplying by 1.0f when we need
|
|
// to use up aSpanPrefPct.
|
|
allocatedPct = aSpanPrefPct *
|
|
(float(scolFrame->GetPrefCoord()) /
|
|
float(nonPctTotalPrefISize));
|
|
} else if (cellMap->GetNumCellsOriginatingInCol(scol) > 0) {
|
|
// distribute equally when all pref isizes are 0
|
|
allocatedPct = aSpanPrefPct / float(nonPctColCount);
|
|
} else {
|
|
allocatedPct = 0.0f;
|
|
}
|
|
// Allocate the percent
|
|
scolFrame->AddSpanPrefPercent(allocatedPct);
|
|
|
|
// To avoid accumulating rounding error from division,
|
|
// subtract this column's values from the totals.
|
|
aSpanPrefPct -= allocatedPct;
|
|
nonPctTotalPrefISize -= scolFrame->GetPrefCoord();
|
|
if (cellMap->GetNumCellsOriginatingInCol(scol) > 0) {
|
|
--nonPctColCount;
|
|
}
|
|
|
|
if (!aSpanPrefPct) {
|
|
// No more span-percent-isize to distribute --> we're done.
|
|
NS_ASSERTION(spanHasNonPctPref ?
|
|
nonPctTotalPrefISize == 0 :
|
|
nonPctColCount == 0,
|
|
"No more pct inline-size to distribute, "
|
|
"but there are still cols that need some.");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
BasicTableLayoutStrategy::DistributeISizeToColumns(nscoord aISize,
|
|
int32_t aFirstCol,
|
|
int32_t aColCount,
|
|
BtlsISizeType aISizeType,
|
|
bool aSpanHasSpecifiedISize)
|
|
{
|
|
NS_ASSERTION(aISizeType != BTLS_FINAL_ISIZE ||
|
|
(aFirstCol == 0 &&
|
|
aColCount == mTableFrame->GetCellMap()->GetColCount()),
|
|
"Computing final column isizes, but didn't get full column range");
|
|
|
|
nscoord subtract = 0;
|
|
// aISize initially includes border-spacing for the boundaries in between
|
|
// each of the columns. We start at aFirstCol + 1 because the first
|
|
// in-between boundary would be at the left edge of column aFirstCol + 1
|
|
for (int32_t col = aFirstCol + 1; col < aFirstCol + aColCount; ++col) {
|
|
if (mTableFrame->ColumnHasCellSpacingBefore(col)) {
|
|
// border-spacing isn't part of the basis for percentages.
|
|
subtract += mTableFrame->GetColSpacing(col - 1);
|
|
}
|
|
}
|
|
if (aISizeType == BTLS_FINAL_ISIZE) {
|
|
// If we're computing final col-isize, then aISize initially includes
|
|
// border spacing on the table's far istart + far iend edge, too. Need
|
|
// to subtract those out, too.
|
|
subtract += (mTableFrame->GetColSpacing(-1) +
|
|
mTableFrame->GetColSpacing(aColCount));
|
|
}
|
|
aISize = NSCoordSaturatingSubtract(aISize, subtract, nscoord_MAX);
|
|
|
|
/*
|
|
* The goal of this function is to distribute |aISize| between the
|
|
* columns by making an appropriate AddSpanCoords or SetFinalISize
|
|
* call for each column. (We call AddSpanCoords if we're
|
|
* distributing a column-spanning cell's minimum or preferred isize
|
|
* to its spanned columns. We call SetFinalISize if we're
|
|
* distributing a table's final isize to its columns.)
|
|
*
|
|
* The idea is to either assign one of the following sets of isizes
|
|
* or a weighted average of two adjacent sets of isizes. It is not
|
|
* possible to assign values smaller than the smallest set of
|
|
* isizes. However, see below for handling the case of assigning
|
|
* values larger than the largest set of isizes. From smallest to
|
|
* largest, these are:
|
|
*
|
|
* 1. [guess_min] Assign all columns their min isize.
|
|
*
|
|
* 2. [guess_min_pct] Assign all columns with percentage isizes
|
|
* their percentage isize, and all other columns their min isize.
|
|
*
|
|
* 3. [guess_min_spec] Assign all columns with percentage isizes
|
|
* their percentage isize, all columns with specified coordinate
|
|
* isizes their pref isize (since it doesn't matter whether it's the
|
|
* largest contributor to the pref isize that was the specified
|
|
* contributor), and all other columns their min isize.
|
|
*
|
|
* 4. [guess_pref] Assign all columns with percentage isizes their
|
|
* specified isize, and all other columns their pref isize.
|
|
*
|
|
* If |aISize| is *larger* than what we would assign in (4), then we
|
|
* expand the columns:
|
|
*
|
|
* a. if any columns without a specified coordinate isize or
|
|
* percent isize have nonzero pref isize, in proportion to pref
|
|
* isize [total_flex_pref]
|
|
*
|
|
* b. otherwise, if any columns without a specified coordinate
|
|
* isize or percent isize, but with cells originating in them,
|
|
* have zero pref isize, equally between these
|
|
* [numNonSpecZeroISizeCols]
|
|
*
|
|
* c. otherwise, if any columns without percent isize have nonzero
|
|
* pref isize, in proportion to pref isize [total_fixed_pref]
|
|
*
|
|
* d. otherwise, if any columns have nonzero percentage isizes, in
|
|
* proportion to the percentage isizes [total_pct]
|
|
*
|
|
* e. otherwise, equally.
|
|
*/
|
|
|
|
// Loop #1 over the columns, to figure out the four values above so
|
|
// we know which case we're dealing with.
|
|
|
|
nscoord guess_min = 0,
|
|
guess_min_pct = 0,
|
|
guess_min_spec = 0,
|
|
guess_pref = 0,
|
|
total_flex_pref = 0,
|
|
total_fixed_pref = 0;
|
|
float total_pct = 0.0f; // 0.0f to 1.0f
|
|
int32_t numInfiniteISizeCols = 0;
|
|
int32_t numNonSpecZeroISizeCols = 0;
|
|
|
|
int32_t col;
|
|
nsTableCellMap *cellMap = mTableFrame->GetCellMap();
|
|
for (col = aFirstCol; col < aFirstCol + aColCount; ++col) {
|
|
nsTableColFrame *colFrame = mTableFrame->GetColFrame(col);
|
|
if (!colFrame) {
|
|
NS_ERROR("column frames out of sync with cell map");
|
|
continue;
|
|
}
|
|
nscoord min_iSize = colFrame->GetMinCoord();
|
|
guess_min += min_iSize;
|
|
if (colFrame->GetPrefPercent() != 0.0f) {
|
|
float pct = colFrame->GetPrefPercent();
|
|
total_pct += pct;
|
|
nscoord val = nscoord(float(aISize) * pct);
|
|
if (val < min_iSize) {
|
|
val = min_iSize;
|
|
}
|
|
guess_min_pct += val;
|
|
guess_pref = NSCoordSaturatingAdd(guess_pref, val);
|
|
} else {
|
|
nscoord pref_iSize = colFrame->GetPrefCoord();
|
|
if (pref_iSize == nscoord_MAX) {
|
|
++numInfiniteISizeCols;
|
|
}
|
|
guess_pref = NSCoordSaturatingAdd(guess_pref, pref_iSize);
|
|
guess_min_pct += min_iSize;
|
|
if (colFrame->GetHasSpecifiedCoord()) {
|
|
// we'll add on the rest of guess_min_spec outside the
|
|
// loop
|
|
nscoord delta = NSCoordSaturatingSubtract(pref_iSize,
|
|
min_iSize, 0);
|
|
guess_min_spec = NSCoordSaturatingAdd(guess_min_spec, delta);
|
|
total_fixed_pref = NSCoordSaturatingAdd(total_fixed_pref,
|
|
pref_iSize);
|
|
} else if (pref_iSize == 0) {
|
|
if (cellMap->GetNumCellsOriginatingInCol(col) > 0) {
|
|
++numNonSpecZeroISizeCols;
|
|
}
|
|
} else {
|
|
total_flex_pref = NSCoordSaturatingAdd(total_flex_pref,
|
|
pref_iSize);
|
|
}
|
|
}
|
|
}
|
|
guess_min_spec = NSCoordSaturatingAdd(guess_min_spec, guess_min_pct);
|
|
|
|
// Determine what we're flexing:
|
|
enum Loop2Type {
|
|
FLEX_PCT_SMALL, // between (1) and (2) above
|
|
FLEX_FIXED_SMALL, // between (2) and (3) above
|
|
FLEX_FLEX_SMALL, // between (3) and (4) above
|
|
FLEX_FLEX_LARGE, // greater than (4) above, case (a)
|
|
FLEX_FLEX_LARGE_ZERO, // greater than (4) above, case (b)
|
|
FLEX_FIXED_LARGE, // greater than (4) above, case (c)
|
|
FLEX_PCT_LARGE, // greater than (4) above, case (d)
|
|
FLEX_ALL_LARGE // greater than (4) above, case (e)
|
|
};
|
|
|
|
Loop2Type l2t;
|
|
// These are constants (over columns) for each case's math. We use
|
|
// a pair of nscoords rather than a float so that we can subtract
|
|
// each column's allocation so we avoid accumulating rounding error.
|
|
nscoord space; // the amount of extra isize to allocate
|
|
union {
|
|
nscoord c;
|
|
float f;
|
|
} basis; // the sum of the statistic over columns to divide it
|
|
if (aISize < guess_pref) {
|
|
if (aISizeType != BTLS_FINAL_ISIZE && aISize <= guess_min) {
|
|
// Return early -- we don't have any extra space to distribute.
|
|
return;
|
|
}
|
|
NS_ASSERTION(!(aISizeType == BTLS_FINAL_ISIZE && aISize < guess_min),
|
|
"Table inline-size is less than the "
|
|
"sum of its columns' min inline-sizes");
|
|
if (aISize < guess_min_pct) {
|
|
l2t = FLEX_PCT_SMALL;
|
|
space = aISize - guess_min;
|
|
basis.c = guess_min_pct - guess_min;
|
|
} else if (aISize < guess_min_spec) {
|
|
l2t = FLEX_FIXED_SMALL;
|
|
space = aISize - guess_min_pct;
|
|
basis.c = NSCoordSaturatingSubtract(guess_min_spec, guess_min_pct,
|
|
nscoord_MAX);
|
|
} else {
|
|
l2t = FLEX_FLEX_SMALL;
|
|
space = aISize - guess_min_spec;
|
|
basis.c = NSCoordSaturatingSubtract(guess_pref, guess_min_spec,
|
|
nscoord_MAX);
|
|
}
|
|
} else {
|
|
space = NSCoordSaturatingSubtract(aISize, guess_pref, nscoord_MAX);
|
|
if (total_flex_pref > 0) {
|
|
l2t = FLEX_FLEX_LARGE;
|
|
basis.c = total_flex_pref;
|
|
} else if (numNonSpecZeroISizeCols > 0) {
|
|
l2t = FLEX_FLEX_LARGE_ZERO;
|
|
basis.c = numNonSpecZeroISizeCols;
|
|
} else if (total_fixed_pref > 0) {
|
|
l2t = FLEX_FIXED_LARGE;
|
|
basis.c = total_fixed_pref;
|
|
} else if (total_pct > 0.0f) {
|
|
l2t = FLEX_PCT_LARGE;
|
|
basis.f = total_pct;
|
|
} else {
|
|
l2t = FLEX_ALL_LARGE;
|
|
basis.c = aColCount;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG_dbaron_off
|
|
printf("ComputeColumnISizes: %d columns in isize %d,\n"
|
|
" guesses=[%d,%d,%d,%d], totals=[%d,%d,%f],\n"
|
|
" l2t=%d, space=%d, basis.c=%d\n",
|
|
aColCount, aISize,
|
|
guess_min, guess_min_pct, guess_min_spec, guess_pref,
|
|
total_flex_pref, total_fixed_pref, total_pct,
|
|
l2t, space, basis.c);
|
|
#endif
|
|
|
|
for (col = aFirstCol; col < aFirstCol + aColCount; ++col) {
|
|
nsTableColFrame *colFrame = mTableFrame->GetColFrame(col);
|
|
if (!colFrame) {
|
|
NS_ERROR("column frames out of sync with cell map");
|
|
continue;
|
|
}
|
|
nscoord col_iSize;
|
|
|
|
float pct = colFrame->GetPrefPercent();
|
|
if (pct != 0.0f) {
|
|
col_iSize = nscoord(float(aISize) * pct);
|
|
nscoord col_min = colFrame->GetMinCoord();
|
|
if (col_iSize < col_min) {
|
|
col_iSize = col_min;
|
|
}
|
|
} else {
|
|
col_iSize = colFrame->GetPrefCoord();
|
|
}
|
|
|
|
nscoord col_iSize_before_adjust = col_iSize;
|
|
|
|
switch (l2t) {
|
|
case FLEX_PCT_SMALL:
|
|
col_iSize = col_iSize_before_adjust = colFrame->GetMinCoord();
|
|
if (pct != 0.0f) {
|
|
nscoord pct_minus_min =
|
|
nscoord(float(aISize) * pct) - col_iSize;
|
|
if (pct_minus_min > 0) {
|
|
float c = float(space) / float(basis.c);
|
|
basis.c -= pct_minus_min;
|
|
col_iSize += NSToCoordRound(float(pct_minus_min) * c);
|
|
}
|
|
}
|
|
break;
|
|
case FLEX_FIXED_SMALL:
|
|
if (pct == 0.0f) {
|
|
NS_ASSERTION(col_iSize == colFrame->GetPrefCoord(),
|
|
"wrong inline-size assigned");
|
|
if (colFrame->GetHasSpecifiedCoord()) {
|
|
nscoord col_min = colFrame->GetMinCoord();
|
|
nscoord pref_minus_min = col_iSize - col_min;
|
|
col_iSize = col_iSize_before_adjust = col_min;
|
|
if (pref_minus_min != 0) {
|
|
float c = float(space) / float(basis.c);
|
|
basis.c -= pref_minus_min;
|
|
col_iSize += NSToCoordRound(
|
|
float(pref_minus_min) * c);
|
|
}
|
|
} else
|
|
col_iSize = col_iSize_before_adjust =
|
|
colFrame->GetMinCoord();
|
|
}
|
|
break;
|
|
case FLEX_FLEX_SMALL:
|
|
if (pct == 0.0f &&
|
|
!colFrame->GetHasSpecifiedCoord()) {
|
|
NS_ASSERTION(col_iSize == colFrame->GetPrefCoord(),
|
|
"wrong inline-size assigned");
|
|
nscoord col_min = colFrame->GetMinCoord();
|
|
nscoord pref_minus_min =
|
|
NSCoordSaturatingSubtract(col_iSize, col_min, 0);
|
|
col_iSize = col_iSize_before_adjust = col_min;
|
|
if (pref_minus_min != 0) {
|
|
float c = float(space) / float(basis.c);
|
|
// If we have infinite-isize cols, then the standard
|
|
// adjustment to col_iSize using 'c' won't work,
|
|
// because basis.c and pref_minus_min are both
|
|
// nscoord_MAX and will cancel each other out in the
|
|
// col_iSize adjustment (making us assign all the
|
|
// space to the first inf-isize col). To correct for
|
|
// this, we'll also divide by numInfiniteISizeCols to
|
|
// spread the space equally among the inf-isize cols.
|
|
if (numInfiniteISizeCols) {
|
|
if (colFrame->GetPrefCoord() == nscoord_MAX) {
|
|
c = c / float(numInfiniteISizeCols);
|
|
--numInfiniteISizeCols;
|
|
} else {
|
|
c = 0.0f;
|
|
}
|
|
}
|
|
basis.c = NSCoordSaturatingSubtract(basis.c,
|
|
pref_minus_min,
|
|
nscoord_MAX);
|
|
col_iSize += NSToCoordRound(
|
|
float(pref_minus_min) * c);
|
|
}
|
|
}
|
|
break;
|
|
case FLEX_FLEX_LARGE:
|
|
if (pct == 0.0f &&
|
|
!colFrame->GetHasSpecifiedCoord()) {
|
|
NS_ASSERTION(col_iSize == colFrame->GetPrefCoord(),
|
|
"wrong inline-size assigned");
|
|
if (col_iSize != 0) {
|
|
if (space == nscoord_MAX) {
|
|
basis.c -= col_iSize;
|
|
col_iSize = nscoord_MAX;
|
|
} else {
|
|
float c = float(space) / float(basis.c);
|
|
basis.c -= col_iSize;
|
|
col_iSize += NSToCoordRound(float(col_iSize) * c);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case FLEX_FLEX_LARGE_ZERO:
|
|
if (pct == 0.0f &&
|
|
!colFrame->GetHasSpecifiedCoord() &&
|
|
cellMap->GetNumCellsOriginatingInCol(col) > 0) {
|
|
|
|
NS_ASSERTION(col_iSize == 0 &&
|
|
colFrame->GetPrefCoord() == 0,
|
|
"Since we're in FLEX_FLEX_LARGE_ZERO case, "
|
|
"all auto-inline-size cols should have zero "
|
|
"pref inline-size.");
|
|
float c = float(space) / float(basis.c);
|
|
col_iSize += NSToCoordRound(c);
|
|
--basis.c;
|
|
}
|
|
break;
|
|
case FLEX_FIXED_LARGE:
|
|
if (pct == 0.0f) {
|
|
NS_ASSERTION(col_iSize == colFrame->GetPrefCoord(),
|
|
"wrong inline-size assigned");
|
|
NS_ASSERTION(colFrame->GetHasSpecifiedCoord() ||
|
|
colFrame->GetPrefCoord() == 0,
|
|
"wrong case");
|
|
if (col_iSize != 0) {
|
|
float c = float(space) / float(basis.c);
|
|
basis.c -= col_iSize;
|
|
col_iSize += NSToCoordRound(float(col_iSize) * c);
|
|
}
|
|
}
|
|
break;
|
|
case FLEX_PCT_LARGE:
|
|
NS_ASSERTION(pct != 0.0f || colFrame->GetPrefCoord() == 0,
|
|
"wrong case");
|
|
if (pct != 0.0f) {
|
|
float c = float(space) / basis.f;
|
|
col_iSize += NSToCoordRound(pct * c);
|
|
basis.f -= pct;
|
|
}
|
|
break;
|
|
case FLEX_ALL_LARGE:
|
|
{
|
|
float c = float(space) / float(basis.c);
|
|
col_iSize += NSToCoordRound(c);
|
|
--basis.c;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Only subtract from space if it's a real number.
|
|
if (space != nscoord_MAX) {
|
|
NS_ASSERTION(col_iSize != nscoord_MAX,
|
|
"How is col_iSize nscoord_MAX if space isn't?");
|
|
NS_ASSERTION(col_iSize_before_adjust != nscoord_MAX,
|
|
"How is col_iSize_before_adjust nscoord_MAX if space isn't?");
|
|
space -= col_iSize - col_iSize_before_adjust;
|
|
}
|
|
|
|
NS_ASSERTION(col_iSize >= colFrame->GetMinCoord(),
|
|
"assigned inline-size smaller than min");
|
|
|
|
// Apply the new isize
|
|
switch (aISizeType) {
|
|
case BTLS_MIN_ISIZE:
|
|
{
|
|
// Note: AddSpanCoords requires both a min and pref isize.
|
|
// For the pref isize, we'll just pass in our computed
|
|
// min isize, because the real pref isize will be at least
|
|
// as big
|
|
colFrame->AddSpanCoords(col_iSize, col_iSize,
|
|
aSpanHasSpecifiedISize);
|
|
}
|
|
break;
|
|
case BTLS_PREF_ISIZE:
|
|
{
|
|
// Note: AddSpanCoords requires both a min and pref isize.
|
|
// For the min isize, we'll just pass in 0, because
|
|
// the real min isize will be at least 0
|
|
colFrame->AddSpanCoords(0, col_iSize,
|
|
aSpanHasSpecifiedISize);
|
|
}
|
|
break;
|
|
case BTLS_FINAL_ISIZE:
|
|
{
|
|
nscoord old_final = colFrame->GetFinalISize();
|
|
colFrame->SetFinalISize(col_iSize);
|
|
|
|
if (old_final != col_iSize) {
|
|
mTableFrame->DidResizeColumns();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
NS_ASSERTION((space == 0 || space == nscoord_MAX) &&
|
|
((l2t == FLEX_PCT_LARGE)
|
|
? (-0.001f < basis.f && basis.f < 0.001f)
|
|
: (basis.c == 0 || basis.c == nscoord_MAX)),
|
|
"didn't subtract all that we added");
|
|
}
|