Files
palemoon27/layout/tables/BasicTableLayoutStrategy.cpp
T
roytam1 fffeb135bb import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1040668 part 2 - Parse and compute text emphasis properties. r=dbaron (0fb79d4709)
- Bug 1040668 part 3 - Add helper function gfxTextRun::GetAdvanceForGlyph. r=jfkthame (f1cf02f5ff)
- Bug 1216427 - Tests for backspacing over a character with variation selector, and over Regional Indicator flag symbols. r=emk (18957bfe77)
- Bug 1216427 - part 1 - Ensure a character+VS sequence or a ligated Regional-Indicator flag symbol is deleted as a single unit when backspacing. r=emk (2776ff8f4a)
- Bug 1216427 - part 2 - Ensure mouse selection does not split up a Regional Indicator flag symbol. r=emk (58eb82e6a1)
- Bug 1040668 part 4 - Add helper function for ensuring a glyph is a complex glyph. r=jfkthame (ba17f7d0c4)
- Bug 1040668 part 5 - Avoid unnecessary allocation inside EnsureComplexGlyph helper function. r=jfkthame (4968a7c68e)
- Bug 1040668 part 6 - Add some specifier on gfxTextRun and gfxShapedWord so that compilers are able to reason out certain optimizations. r=jfkthame (69ca3eb959)
- Bug 1040668 part 7 - Add NO_EMPHASIS_MARK flag in CompressedGlyph. r=jfkthame (34e9d8a6a6)
- Bug 1227001 part 1 - Remove SetupBreakSinksFlags from BuildTextRunsScanner. r=jfkthame (520b1ba111)
- Bug 1227001 part 2 - Remove no longer used mExistingTextRun from BreaSink. r=jfkthame (201782a78c)
- Bug 1227001 part 3 - Remove no longer used mChangedBreaks from BreakSink. r=jfkthame (e754e2b13f)
- Bug 1040668 part 8 - Setup text emphasis for text run. r=jfkthame (376377180e)
- Bug 1040668 part 9 - Compute overflow from text-shadow after text decorations. r=dbaron (05c9bd08c2)
- Bug 1040668 part 10 - Implement emphasis mark rendering. r=jfkthame (4d270afca8)
- Bug 1040668 part 11 - Move line leadings adjusting code into a separate function in nsLineLayout. r=dholbert (fd4dd20ca5)
- Bug 1040668 part 12 - Add line leadings for emphasis marks if necessary. r=dholbert (138add5ff7)
- Bug 1040668 part 13 - Move first part of nsStyleFont::GetLanguage to nsPresContext::GetContentLanguage. r=dbaron (1e872d2a58)
- Bug 1040668 part 14 - Add helper function nsStyleUtil::MatchesLanguagePrefix for doing simple language matching. r=dbaron (9322a02369)
- Bug 1040668 part 15 - Make the default value of text-emphasis-position aware of the language. r=dbaron (6587c628da)
- Bug 1040668 part 16 - Add reftests for text-emphasis. r=dbaron (9940d65182)
- Bug 1040668 followup - Use monospace for text-emphasis reftests. rs=dbaron on a CLOSED TREE (fb7598c3ea)
- Bug 1040668 followup 2 - Disable failing reftests of text-emphasis on Windows XP. (7c3f24ac22)
- Bug 1040668 followup 3 - Wrap lang attribute mapping code in NS_STYLE_INHERIT_BIT test. r=dbaron (640e3b7b8f)
- Bug 1219145 - nsRefreshDriver::IsJankCritical(). r=hiro To refine its alerts, Performance Stats API needs to be able to know whether a long-running operation is actually causing user-visible jank in the current process. This patch introduces a trivial API that lets clients ask the refresh driver whether any kind of animation is ongoing. (7c0868d7c4)
- more missing XP theme stuff (637af0c6a0)
- Bug 1210261. Tick root refresh driver last. r=mattwoodrow (dae1a325fa)
- Bug 1221674 Part 2: Correct for negative content delay values. r=avih (9b9811c41c)
- Bug 1211334 - Check if presshell is still available after dispatching transition events; r=mats (8a044a462c)
- Bug 1211599 - Only allow whitelisted histograms to have > 100 buckets. r=nfroyd (d467e84130)
- Bug 1219733 - Allow a 'bug_numbers' field in Histograms.json entries. r=vladan (8e63a713ec)
- Bug 1222044 - Only allow lists of alert_emails r=vladan (1d5fcb009d)
- Bug 1168263 - Add a flags parameter to GetResultingTransformMatrix instead of using bools. r=roc (ec5224f9af)
- Bug 1168263 - Remove TransformRectOut since it's unused. r=roc (d20a79ae0e)
- Bug 1215406 - Part 1: Remove NS_STYLE_ANIMATION_DIRECTION_XXX and NS_STYLE_ANIMATION_FILL_MODE_XXX. r=heycam (4bd7f8116b)
- Bug 1215406 - Part 2: Change the types of direction and fillmode in StyleAnimation. r=heycam (e06323c81b)
- Bug 1215406 - Part 3: Change the types of direction and fillmode in AnimationTiming. r=heycam (e5454d3ea5)
- Bug 1215406 - Part 4: Add KeyframeEffectOptions. r=smaug Add KeyframeEffectOptions in KeyframeEffect.webidl (0ce3372fd1)
- Bug 1215406 - Part 5: Implement KeyframeEffectOptions in KeyframeEffectReadOnly constructor. r=birtles (a472e9ac5f)
- tch 2 - Use an enum class for NS_STYLE_BOX_SIZING_*. r=heycam (4897b7b8ff)
- Bug 1218195, mark MutationObserver as observing in all the nested DOM mutations, r=bz (48a4aa8a91)
- Bug 1172870 - Part 3 - Fix openWindow mochitest to work on e10s (574cc6fa4d)
- Bug 1223265 - Fix -Wunreachable-code and -Wimplicit-fallthrough warnings in dom/bindings and dom/ipc. r=khuey (9eab632140)
- Bug 1189195 - Fix PContentPermissionRequest shutdown () r=fabrice (6bc1a681f5)
- Bug 1210508 - Handle null OriginAttributes from JS-implemented nsILoadContext. r=me (2f71edb9d7)
- Bug 1224596 part 1. Add a version of WorkerMainThreadRunnable::Dispatch that takes an ErrorResult to report failure to dispatch on. r=khuey (e60a0fb115)
- Bug 1224596 part 2. Switch Navigator to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (d9298a4763)
- Bug 1224596 part 3. Make some WebSocket(Impl) methods whose return value is totally ignored void. r=khuey (1d04b52d44)
- Bug 1224596 part 4. Switch WebSocket to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (aa06e6417b)
- Bug 1224596 part 5. Switch nsPerformance to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (0303b7de09)
- Bug 1224596 part 6. Switch BroadcastChannel to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (feacc21f63)
- Bug 1224636. Fix some code in ImageBitmap that rejects a promise with an ErrorResult, then keeps trying to use that ErrorResult. r=kaku (89b769fe07)
- Bug 1224596 part 7. Switch ImageBitmap to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (e21b0a4a0a)
- Bug 1183954, Don't leak nsStructuredCloneContainer (use of 'auto' is error prone), r=leak (1a9b30f2ca)
- Bug 1114554 - Patch 9 - Fixed crash in b2g-desktop tests. r=nsm (6b12c6d121)
- Bug 1189090 - Rework the nsISupports implementation in the ScopeCheckingGetCallback and its subclasses; r=nsm (6bea544597)
- Bug 1187018 - Ensure feature is nulled out if it does not get added. r=khuey (9d7439498a)
- Bug 1224596 part 8. Switch Notification to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (03f0f6877f)
- Bug 1196079 - Always try to release Notification via normal WorkerRunnable first. r=wchen (c093253d6f)
- Bug 1203324 - disable notifications on serviceworkers. r=ehsan,wchen (aa39310dc1)
- Bug 1199901 - GetOrigin() fails cleanly instead of asserting principal. r=wchen (148c634a4f)
- Bug 1199901 - Clear mObserver when WorkerNotificationObserver is destroyed. r=wchen (6d5cd99183)
- Bug 1199901 - Bustage fix due to rebase. a=bustage (344bd62af5)
- Bug 1225470 Report a message to the console when a service worker waitUntil() is rejected. r=baku (610da2eec6)
- Bug 1217909 P1 Report service worker exceptions to controlled documents. r=catalinb (f8bd4677d5)
- Bug 1216566 - Fix a bug in nsIServiceWorkerManager.getAllRegistrations;r=catalinb (ed3e14ab43)
- Bug 1219205 - ServiceWorkerInfo should be an XPCOM object;r=catalinb (677a6f1ffd)
- Bug 1217909 P2 Track registering documents as weak reference so SWM can report errors to them. r=catalinb (4233dc3edc)
- Bug 1217909 P3 Refactor service worker register()/update() to reject only with SecurityErr or TypeErr. r=catalinb (c6891a7fae)
- Bug 1220740 - nsIServiceWorkerRegistrationInfo should emit an event when its scriptSpec property changes;r=amarchesini (5772bb5914)
- Bug 1207727 - Add WPT tests for service worker update algorithm. r=bkelly (a4812571a1)
- Bug 1217367 - Service workers update algorithm optimization. r=bkelly (e377debad1)
- Bug 1226479. Change ErrorResult::ThrowTypeError/ThrowRangeError to take string references, not pointers. r=mccr8 (0804899666)
- Bug 1224659 - Worker DataStore code should not use ErrorResult cross threads, r=bz (aef03b0fdd)
- Bug 1224596 part 9. Switch DataStore to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (1eb1c427f2)
- Bug 1224596 part 10. Switch DataStoreCursor to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (114af8021b)
- Bug 1224596 part 11. Switch WorkerNavigator to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (b2347a0c49)
- Bug 1224596 part 12. Switch ServiceWorkerRegistration to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (d1ff076836)
- Bug 1224596 part 13. Switch gfxUtils to using the new WorkerMainThreadRunnable::Dispatch signature. r=khuey (a523997588)
- Bug 1224007 part 1. Rename ThrowMethodFailed to MaybeSetPendingException and make it an ErrorResult instance method. r=peterv (bdf0891f54)
- Bug 1224007 part 2. Make the various ErrorResult::Report* methods private, so consumers all go through MaybeSetPendingException and rename them to more clearly indicate what they're actually doing. r=peterv (48f483c153)
- Bug 1203151 - Allow disabling of screen wakelocks for video elements. r=baku (6bd9ff6916)
- Bug 1224007 part 4. Fix some cases in which ErrorResult instances are destroyed without doing anything useful with exceptions on them. r=peterv (e328785e5d)
- Bug 1224007 part 5. Get rid of ErrorResult::StealJSException. r=peterv (db19cfb31e)
- Bug 1224007 part 3. Push down WouldReportJSException into MaybeSetPendingException, since anyone calling the latter will propagate the JS exception as needed. r=peterv (1d3b7b415d)
- Bug 1224007 part 6. Change MaybeSetPendingException to set the ErrorResult state to "not failed", just like SuppressException and StealNSResult already do, and assert in the destructor that the ErrorResult is not Failed(). (a028838e8d)
- Bug 1213815 - Update URLSearchParams and URLUtils in webidl files, r=bz (28fb8f7de5)
- Bug 1213815 - dom/webidl/HTMLHyperlinkElementUtils and URL don't need to throw exceptions as we did before, r=bz (b13dc3bcb9)
- Bug 1224596 part 14. Switch URL to using the new WorkerMainThreadRunnable::Dispatch signature. r=baku (232677e50e)
- fix updating the backport (9e958da5ca)
- Bug 1224596 part 16. Switch Fetch to using the new WorkerMainThreadRunnable::Dispatch signature. r=bkelly (939e338f22)
- Bug 1224596 part 17. Remove the old WorkerMainThreadRunnable::Dispatch signature. r=khuey (5a70429ec8)
- Bug 1143575. Don't report negative frame delays. r=cpearce (7d8bc0f753)
- Bug 1187371 - Get rid of dom.broadcastChannel.enabled pref, r=bz (9335b7ae90)
- Bug 1196514 - remove dom.messagechannel.enabled pref, r=smaug (31e06119b4)
- Bug 1166356 - Properly detect double-caching in nsXULPrototypeCache; r=ehsan (29df9ffb2d)
- Bug 1168916 - Get rid of redundant pref callback in nsXULPrototypeCache; r=janv (9f37fff405)
- Bug 1139099: Dispatch DOMDocElementInserted to match the document-element-inserted observer notification. r=mrbkap (6565e4b924)
- Bug 1187068 - Tell the cycle collector about nsContentSink::mCSSLoader. r=heycam (4ae23eb26c)
- Bug 1172189 - Fix overflow in nsXULContentSink.cpp. r=ehsan (cc6330f5de)
- Bug 1126010 - XULContentSinkImpl::mParser should be an nsRefPtr. r=smaug (d6bb567692)
- Bug 1147946, part 7 - Remove trailing whitespace from nsXULContentSink.cpp. r=baku (cdcadbfeeb)
- Bug 1147946, part 1 - Tuck elses in nsXULContentSink.cpp. r=baku (26fd806676)
- Bug 1147946, part 2 - Move body of check inside prior if in XULContentSinkImpl::OpenScript(). r=baku (b509455bdb)
- Bug 1147946, part 3 - Eliminate unused case for non-JS scripting languages in XULContentSinkImpl::OpenScript(). r=baku (4136933cc2)
- Bug 1147946, part 4 - Use an early return in XULContentSinkImpl::OpenScript(). r=baku (c3e293474b)
- Bug 1147946, part 5 - Don't use the generic nsIProgrammingLanguage enum in XULContentSinkImpl::OpenScript(). r=baku (89a124e23f)
- Bug 1147946, part 6 - Remove some useless null checks on infallible new in XULContentSinkImpl. r=baku (1ac57e8c3a)
- Bug 1221351 P1 ServiceWorkerContainer and ServiceWorkerRegistration should not crash for null window owner. r=catalinb (1a72748632)
- Bug 1212867 - Node.isEqualNode() should ignore internal subsets; r=bzBug (99b166ffee)
- Bug 492933 - getElementsByTagName should match on localName not tagName, r=smaug (d0c6ceabf1)
- Bug 912470 part 1 - Implement Encoding Standard-compliant big5 decoder. r=emk. (c680b0ae9b)
- Bug 1170932: Test handling of unmapped characters in unicode-to-codepage encoders (ca36bcbd35)
- fix style (95a90bfe3a)
- Bug 1170794 - patch 2 - Improve the length check of the input in nsUnicode*::GetMaxLength, r=dveditz (aa864d656f)
- Bug 1170794 followup: Add 'override' annotations to Convert() & Reset() methods in intl/uconv. rs=ehsan (bb3e6e492e)
- Bug 1176462 - Remove nsTableDecoderSupport. r=smontagu (f4a86c44b3)
- Bug 1169248 - Fix GBK/GB18030 encoders. r=smontagu (ed946e1ee1)
- Bug 1155539 - Remove obsolete encoding decoder telemetry probes. r=emk. (44e15bfb40)
- Bug 912470 part 2 - Implement Encoding Standard-compliant big5 encoder. r=emk. (5cca2dc4a0)
- Bug 912470 addendum - Pass override static analysis. r=emk. (c163bffeb4)
- Bug 1170932: Improve error handling for the gbk encoder, r=emk (30e95b34a5)
- Bug 1202366 - Implement the encoder error mode "HTML" for nsFormSubmission without nsISaveAsCharset. r=NOT_emk. (ebc8b542dd)
- update manifest (6cc19172cc)
- Bug 1197309 - remove PR_snprintf calls in intl/; r=froydnj (79fcdfa845)
- Bug 1214619 - Remove nsISaveAsCharset as much as possible without breaking extensions in popular use. r=emk. (89b71b3d87)
- Bug 1214857. Store the document-is-HTML state directly in nsContentList instead of refetching from the node being matched. r=smaug (4c4fbf469e)
- Bug 1221351 P2 Add a web-platform-test to check for crash when calling .register() on closed window. r=catalinb (eeb30c1bba)
- Bug 1221351 P3 Fix test name in register-closed-window.https.html. a=testonly (5bfa840044)
- Bug 1224436: Remove enumerator usage in ServiceWorkerManager.cpp. r=njn (b8cb094d3c)
- Bug 1223716. Make HTMLCollection check for the element being HTML before checking for its name inside its named getter. r=bkelly (977e0bff5a)
- Bug 1180737 - Add update-test.py and update test to latest version. r=bkelly. (59faa36d5c)
- Bug 1217909 P4 Extend wpt tests to verify update() promise values for different script failures. r=catalinb (a2f7352a3a)
- Bug 1217909 P5 Add wpt test case for fetch event handlers that throw. r=catalinb (56a77f611c)
- Bug 1217909 P6 Fix wpt registration.https.html to expect TypeError for script evaluation errors. r=catalinb (3de8a45688)
- Bug 1217909 P7 Fix mochitest to expect TypeError when serviceWorker.register() rejects. r=catalinb (6e8841c41e)
- Bug 1217909 P8 Track navigation interceptions per scope in ServiceWorkerManager. r=catalinb (6705ba8337)
- Bug 1217909 P9 Report exceptions to windows performing an intercepted navigation. r=catalinb (52f9fece14)
- Bug 1217909 P10 Remove stale nsTArray when the last registering document for a scope is removed. r=catalinb (b739bcc3b2)
- Bug 1217909 P11 Only report errors to documents that are active and not in the bfcache. r=catalinb (5ffd633af2)
- Bug 1223378 Tighten service worker register() principal checks. r=baku (478785f2cc)
- Bug 1189685 - Part 1: Ensure that the state of all ServiceWorker instances is up to date when dispatching statechange events; r=bkelly (2bd9b78c58)
- Bug 1189685 - Part 2: Make synced-state.https.html pass; r=bkelly (029f942d8c)
- Bug 1220740 - nsIServiceWorkerRegistrationInfo should emit an event when its worker properties change;r=amarchesini (8243a3debc)
- Bug 1186856 ServiceWorker .register() should always stop current registration from uninstalling. r=jdm (ec7d6e0e7c)
- Bug 1224941 Don't crash during ServiceWorker life cycle event dispatch if window is gone. r=baku (a3f45af3e4)
- Bug 1180754 - Get serviceworkerobject-scripturl test passing. r=bkelly (c7979bef47)
- Bug 1201498 - Service worker update should compare scriptURL to worker URL without fragment, r=bkelly (914f630528)
- Bug 594505 - Remove obsolete comment since this bug has now been fixed. r=me DONTBUILD (44f3a15b91)
- Bug 1221840. Support repeating images in 1 axis. r=seth (449ea3e97e)
- const-var (5433688051)
- Bug 1574573 - Disambiguate a use of Handle in XPCShellEnvironment.cpp r=Ehsan (15b44177d1)
- clean up warnings (6e64313d0c)
2023-02-14 09:56:52 +08:00

1075 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 StyleBoxSizing::Content:
boxSizingToBorderEdge = offsets.hPadding + offsets.hBorder;
break;
case StyleBoxSizing::Padding:
minCoord += offsets.hPadding;
prefCoord += offsets.hPadding;
boxSizingToBorderEdge = offsets.hBorder;
break;
case StyleBoxSizing::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");
}