Merge inbound to central, a=merge

This commit is contained in:
Wes Kocher 2015-09-24 16:46:34 -07:00
commit 4a23e18b0a
177 changed files with 2998 additions and 1286 deletions

View File

@ -410,6 +410,8 @@
@RESPATH@/components/AlarmsManager.manifest
@RESPATH@/components/FeedProcessor.manifest
@RESPATH@/components/FeedProcessor.js
@RESPATH@/components/PackagedAppUtils.manifest
@RESPATH@/components/PackagedAppUtils.js
@RESPATH@/components/BrowserFeeds.manifest
@RESPATH@/components/FeedConverter.js
@RESPATH@/components/FeedWriter.js

View File

@ -369,6 +369,8 @@
@RESPATH@/components/BrowserElementParent.js
@RESPATH@/components/FeedProcessor.manifest
@RESPATH@/components/FeedProcessor.js
@RESPATH@/components/PackagedAppUtils.js
@RESPATH@/components/PackagedAppUtils.manifest
@RESPATH@/browser/components/BrowserFeeds.manifest
@RESPATH@/browser/components/FeedConverter.js
@RESPATH@/browser/components/FeedWriter.js

View File

@ -12,6 +12,7 @@
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/Maybe.h"
#include "mozilla/RefCounted.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"

View File

@ -942,6 +942,7 @@ NS_INTERFACE_MAP_BEGIN(nsDocShell)
NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands)
NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager)
NS_INTERFACE_MAP_ENTRY(nsINetworkInterceptController)
NS_INTERFACE_MAP_ENTRY(nsIDeprecationWarner)
NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
NS_IMETHODIMP
@ -14060,3 +14061,13 @@ nsDocShell::InFrameSwap()
} while (shell);
return false;
}
NS_IMETHODIMP
nsDocShell::IssueWarning(uint32_t aWarning, bool aAsError)
{
nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
if (doc) {
doc->WarnOnceAbout(nsIDocument::DeprecatedOperations(aWarning), aAsError);
}
return NS_OK;
}

View File

@ -58,6 +58,7 @@
#include "prtime.h"
#include "nsRect.h"
#include "Units.h"
#include "nsIDeprecationWarner.h"
namespace mozilla {
namespace dom {
@ -145,6 +146,7 @@ class nsDocShell final
, public nsIClipboardCommands
, public nsIDOMStorageManager
, public nsINetworkInterceptController
, public nsIDeprecationWarner
, public mozilla::SupportsWeakPtr<nsDocShell>
{
friend class nsDSURIContentListener;
@ -176,6 +178,7 @@ public:
NS_DECL_NSICLIPBOARDCOMMANDS
NS_DECL_NSIWEBSHELLSERVICES
NS_DECL_NSINETWORKINTERCEPTCONTROLLER
NS_DECL_NSIDEPRECATIONWARNER
NS_FORWARD_SAFE_NSIDOMSTORAGEMANAGER(TopSessionStorageManager())
NS_IMETHOD Stop() override

View File

@ -252,6 +252,18 @@ this.AlarmService = {
debug("_onAlarmFired()");
if (this._currentAlarm) {
let currentAlarmTime = this._getAlarmTime(this._currentAlarm);
// If a alarm fired before the actual time that the current
// alarm should occur, we reset this current alarm.
if (currentAlarmTime > Date.now()) {
let currentAlarm = this._currentAlarm;
this._currentAlarm = currentAlarm;
this._debugCurrentAlarm();
return;
}
this._removeAlarmFromDb(this._currentAlarm.id, null);
this._notifyAlarmObserver(this._currentAlarm);
this._currentAlarm = null;
@ -414,6 +426,16 @@ this.AlarmService = {
// the non-serializable callback to the in-memory object.
aNewAlarm['alarmFiredCb'] = aAlarmFiredCb;
// If the new alarm already expired at this moment, we directly
// notify this alarm
let aNewAlarmTime = this._getAlarmTime(aNewAlarm);
if (aNewAlarmTime < Date.now()) {
aSuccessCb(aNewId);
this._removeAlarmFromDb(aNewAlarm.id, null);
this._notifyAlarmObserver(aNewAlarm);
return;
}
// If there is no alarm being set in system, set the new alarm.
if (this._currentAlarm == null) {
this._currentAlarm = aNewAlarm;
@ -425,7 +447,6 @@ this.AlarmService = {
// If the new alarm is earlier than the current alarm, swap them and
// push the previous alarm back to the queue.
let alarmQueue = this._alarmQueue;
let aNewAlarmTime = this._getAlarmTime(aNewAlarm);
let currentAlarmTime = this._getAlarmTime(this._currentAlarm);
if (aNewAlarmTime < currentAlarmTime) {
alarmQueue.unshift(this._currentAlarm);

View File

@ -16,6 +16,7 @@ const APP_TRUSTED_ROOTS= ["AppMarketplaceProdPublicRoot",
"AppMarketplaceDevPublicRoot",
"AppMarketplaceDevReviewersRoot",
"AppMarketplaceStageRoot",
"PrivilegedPackageRoot",
"AppXPCShellRoot"];
this.TrustedRootCertificate = {

View File

@ -41,3 +41,4 @@ DEPRECATED_OPERATION(DataContainerEvent)
DEPRECATED_OPERATION(Window_Controllers)
DEPRECATED_OPERATION(ImportXULIntoContent)
DEPRECATED_OPERATION(PannerNodeDoppler)
DEPRECATED_OPERATION(AppCache)

View File

@ -158,8 +158,10 @@ IndexedDBTransactionAbortNavigation=An IndexedDB transaction that was not yet co
IgnoringWillChangeOverBudgetWarning=Will-change memory consumption is too high. Budget limit is the document surface area multiplied by %1$S (%2$S px). Occurrences of will-change over the budget will be ignored.
# LOCALIZATION NOTE: Do not translate "ServiceWorker".
HittingMaxWorkersPerDomain=A ServiceWorker could not be started immediately because other documents in the same origin are already using the maximum number of workers. The ServiceWorker is now queued and will be started after some of the other workers have completed.
# LOCALIZATION NOTE: Do no translate "setVelocity", "PannerNode", "AudioListener", "speedOfSound" and "dopplerFactor"
# LOCALIZATION NOTE: Do not translate "setVelocity", "PannerNode", "AudioListener", "speedOfSound" and "dopplerFactor"
PannerNodeDopplerWarning=Use of setVelocity on the PannerNode and AudioListener, and speedOfSound and dopplerFactor on the AudioListener are deprecated and those members will be removed. For more help https://developer.mozilla.org/en-US/docs/Web/API/AudioListener#Deprecated_features
# LOCALIZATION NOTE: Do not translate "Application Cache API", "AppCache" and "ServiceWorker".
AppCacheWarning=The Application Cache API (AppCache) is deprecated and will be removed at a future date. Please consider using ServiceWorker for offline support.
# LOCALIZATION NOTE: Do not translate "Worker".
EmptyWorkerSourceWarning=Attempting to create a Worker from an empty source. This is probably unintentional.
# LOCALIZATION NOTE: Do not translate "ServiceWorker".

View File

@ -930,8 +930,10 @@ MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample)
// in this case, we'll just decode forward. Bug 1026330.
mCurrentSeek.mTarget.mType = SeekTarget::Accurate;
}
if (mCurrentSeek.mTarget.mType == SeekTarget::PrevSyncPoint) {
// Non-precise seek; we can stop the seek at the first sample.
if (mCurrentSeek.mTarget.mType == SeekTarget::PrevSyncPoint ||
mPendingSeek.Exists()) {
// Non-precise seek; or a pending seek exists ; we can stop the seek
// at the first sample.
Push(video, MediaData::VIDEO_DATA);
} else {
// We're doing an accurate seek. We still need to discard
@ -2728,19 +2730,19 @@ MediaDecoderStateMachine::DropAudioUpToSeekTarget(MediaData* aSample)
mCurrentSeek.Exists() &&
mCurrentSeek.mTarget.mType == SeekTarget::Accurate);
CheckedInt64 startFrame = UsecsToFrames(audio->mTime,
mInfo.mAudio.mRate);
CheckedInt64 targetFrame = UsecsToFrames(mCurrentSeek.mTarget.mTime,
mInfo.mAudio.mRate);
if (!startFrame.isValid() || !targetFrame.isValid()) {
CheckedInt64 sampleDuration =
FramesToUsecs(audio->mFrames, mInfo.mAudio.mRate);
if (!sampleDuration.isValid()) {
return NS_ERROR_FAILURE;
}
if (startFrame.value() + audio->mFrames <= targetFrame.value()) {
if (audio->mTime + sampleDuration.value() <= mCurrentSeek.mTarget.mTime) {
// Our seek target lies after the frames in this AudioData. Don't
// push it onto the audio queue, and keep decoding forwards.
return NS_OK;
}
if (startFrame.value() > targetFrame.value()) {
if (audio->mTime > mCurrentSeek.mTarget.mTime) {
// The seek target doesn't lie in the audio block just after the last
// audio frames we've seen which were before the seek target. This
// could have been the first audio data we've seen after seek, i.e. the
@ -2756,23 +2758,27 @@ MediaDecoderStateMachine::DropAudioUpToSeekTarget(MediaData* aSample)
// The seek target lies somewhere in this AudioData's frames, strip off
// any frames which lie before the seek target, so we'll begin playback
// exactly at the seek target.
NS_ASSERTION(targetFrame.value() >= startFrame.value(),
NS_ASSERTION(mCurrentSeek.mTarget.mTime >= audio->mTime,
"Target must at or be after data start.");
NS_ASSERTION(targetFrame.value() < startFrame.value() + audio->mFrames,
NS_ASSERTION(mCurrentSeek.mTarget.mTime < audio->mTime + sampleDuration.value(),
"Data must end after target.");
int64_t framesToPrune = targetFrame.value() - startFrame.value();
if (framesToPrune > audio->mFrames) {
CheckedInt64 framesToPrune =
UsecsToFrames(mCurrentSeek.mTarget.mTime - audio->mTime, mInfo.mAudio.mRate);
if (!framesToPrune.isValid()) {
return NS_ERROR_FAILURE;
}
if (framesToPrune.value() > audio->mFrames) {
// We've messed up somehow. Don't try to trim frames, the |frames|
// variable below will overflow.
DECODER_WARN("Can't prune more frames that we have!");
return NS_ERROR_FAILURE;
}
uint32_t frames = audio->mFrames - static_cast<uint32_t>(framesToPrune);
uint32_t frames = audio->mFrames - static_cast<uint32_t>(framesToPrune.value());
uint32_t channels = audio->mChannels;
nsAutoArrayPtr<AudioDataValue> audioData(new AudioDataValue[frames * channels]);
memcpy(audioData.get(),
audio->mAudioData.get() + (framesToPrune * channels),
audio->mAudioData.get() + (framesToPrune.value() * channels),
frames * channels * sizeof(AudioDataValue));
CheckedInt64 duration = FramesToUsecs(frames, mInfo.mAudio.mRate);
if (!duration.isValid()) {

View File

@ -1485,6 +1485,7 @@ MediaManager::MediaManager()
: mMediaThread(nullptr)
, mMutex("mozilla::MediaManager")
, mBackend(nullptr) {
mPrefs.mFreq = 1000; // 1KHz test tone
mPrefs.mWidth = 0; // adaptive default
mPrefs.mHeight = 0; // adaptive default
mPrefs.mFPS = MediaEngine::DEFAULT_VIDEO_FPS;
@ -1497,8 +1498,8 @@ MediaManager::MediaManager()
GetPrefs(branch, nullptr);
}
}
LOG(("%s: default prefs: %dx%d @%dfps (min %d)", __FUNCTION__,
mPrefs.mWidth, mPrefs.mHeight, mPrefs.mFPS, mPrefs.mMinFPS));
LOG(("%s: default prefs: %dx%d @%dfps (min %d), %dHz test tones", __FUNCTION__,
mPrefs.mWidth, mPrefs.mHeight, mPrefs.mFPS, mPrefs.mMinFPS, mPrefs.mFreq));
}
NS_IMPL_ISUPPORTS(MediaManager, nsIMediaManagerService, nsIObserver)
@ -2512,6 +2513,7 @@ MediaManager::GetPrefs(nsIPrefBranch *aBranch, const char *aData)
GetPref(aBranch, "media.navigator.video.default_height", aData, &mPrefs.mHeight);
GetPref(aBranch, "media.navigator.video.default_fps", aData, &mPrefs.mFPS);
GetPref(aBranch, "media.navigator.video.default_minfps", aData, &mPrefs.mMinFPS);
GetPref(aBranch, "media.navigator.audio.fake_frequency", aData, &mPrefs.mFreq);
}
nsresult
@ -2544,6 +2546,7 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
prefs->RemoveObserver("media.navigator.video.default_height", this);
prefs->RemoveObserver("media.navigator.video.default_fps", this);
prefs->RemoveObserver("media.navigator.video.default_minfps", this);
prefs->RemoveObserver("media.navigator.audio.fake_frequency", this);
}
// Close off any remaining active windows.

View File

@ -25,20 +25,29 @@ namespace mozilla {
using layers::PlanarYCbCrImage;
static inline CheckedInt64 SaferMultDiv(int64_t aValue, uint32_t aMul, uint32_t aDiv) {
int64_t major = aValue / aDiv;
int64_t remainder = aValue % aDiv;
return CheckedInt64(remainder) * aMul / aDiv + major * aMul;
}
// Converts from number of audio frames to microseconds, given the specified
// audio rate.
CheckedInt64 FramesToUsecs(int64_t aFrames, uint32_t aRate) {
return (CheckedInt64(aFrames) * USECS_PER_S) / aRate;
return SaferMultDiv(aFrames, USECS_PER_S, aRate);
}
media::TimeUnit FramesToTimeUnit(int64_t aFrames, uint32_t aRate) {
return (media::TimeUnit::FromMicroseconds(aFrames) * USECS_PER_S) / aRate;
int64_t major = aFrames / aRate;
int64_t remainder = aFrames % aRate;
return media::TimeUnit::FromMicroseconds(major) * USECS_PER_S +
(media::TimeUnit::FromMicroseconds(remainder) * USECS_PER_S) / aRate;
}
// Converts from microseconds to number of audio frames, given the specified
// audio rate.
CheckedInt64 UsecsToFrames(int64_t aUsecs, uint32_t aRate) {
return (CheckedInt64(aUsecs) * aRate) / USECS_PER_S;
return SaferMultDiv(aUsecs, aRate, USECS_PER_S);
}
// Format TimeUnit as number of frames at given rate.

View File

@ -54,6 +54,12 @@ public:
static const int DEFAULT_169_VIDEO_HEIGHT = 720;
static const int DEFAULT_AUDIO_TIMER_MS = 10;
#ifndef MOZ_B2G
static const int DEFAULT_SAMPLE_RATE = 32000;
#else
static const int DEFAULT_SAMPLE_RATE = 16000;
#endif
/* Populate an array of video sources in the nsTArray. Also include devices
* that are currently unavailable. */
virtual void EnumerateVideoDevices(dom::MediaSourceEnum,
@ -197,6 +203,7 @@ public:
int32_t mHeight;
int32_t mFPS;
int32_t mMinFPS;
int32_t mFreq; // for test tones (fake:true)
// mWidth and/or mHeight may be zero (=adaptive default), so use functions.

View File

@ -26,7 +26,7 @@
#include "YuvStamper.h"
#endif
#define AUDIO_RATE 16000
#define AUDIO_RATE mozilla::MediaEngine::DEFAULT_SAMPLE_RATE
#define AUDIO_FRAME_LENGTH ((AUDIO_RATE * MediaEngine::DEFAULT_AUDIO_TIMER_MS) / 1000)
namespace mozilla {
@ -302,15 +302,16 @@ class SineWaveGenerator
{
public:
static const int bytesPerSample = 2;
static const int millisecondsPerSecond = 1000;
static const int frequency = 1000;
static const int millisecondsPerSecond = PR_MSEC_PER_SEC;
explicit SineWaveGenerator(int aSampleRate) :
mTotalLength(aSampleRate / frequency),
explicit SineWaveGenerator(uint32_t aSampleRate, uint32_t aFrequency) :
mTotalLength(aSampleRate / aFrequency),
mReadLength(0) {
MOZ_ASSERT(mTotalLength * frequency == aSampleRate);
// If we allow arbitrary frequencies, there's no guarantee we won't get rounded here
// We could include an error term and adjust for it in generation; not worth the trouble
//MOZ_ASSERT(mTotalLength * aFrequency == aSampleRate);
mAudioBuffer = new int16_t[mTotalLength];
for(int i = 0; i < mTotalLength; i++) {
for (int i = 0; i < mTotalLength; i++) {
// Set volume to -20db. It's from 32768.0 * 10^(-20/20) = 3276.8
mAudioBuffer[i] = (3276.8f * sin(2 * M_PI * i / mTotalLength));
}
@ -397,8 +398,9 @@ MediaEngineDefaultAudioSource::Allocate(const dom::MediaTrackConstraints &aConst
}
mState = kAllocated;
// generate 1Khz sine wave
mSineGenerator = new SineWaveGenerator(AUDIO_RATE);
// generate sine wave (default 1KHz)
mSineGenerator = new SineWaveGenerator(AUDIO_RATE,
static_cast<uint32_t>(aPrefs.mFreq ? aPrefs.mFreq : 1000));
return NS_OK;
}

View File

@ -137,6 +137,7 @@ public:
, mChannel(-1)
, mInitDone(false)
, mStarted(false)
, mSampleFrequency(MediaEngine::DEFAULT_SAMPLE_RATE)
, mEchoOn(false), mAgcOn(false), mNoiseOn(false)
, mEchoCancel(webrtc::kEcDefault)
, mAGC(webrtc::kAgcDefault)
@ -225,6 +226,7 @@ private:
nsString mDeviceName;
nsCString mDeviceUUID;
uint32_t mSampleFrequency;
bool mEchoOn, mAgcOn, mNoiseOn;
webrtc::EcModes mEchoCancel;
webrtc::AgcModes mAGC;

View File

@ -19,9 +19,8 @@
#define ENCODING "L16"
#define DEFAULT_PORT 5555
#define SAMPLE_RATE 256000
#define SAMPLE_FREQUENCY 16000
#define SAMPLE_LENGTH ((SAMPLE_FREQUENCY*10)/1000)
#define SAMPLE_RATE(freq) ((freq)*2*8) // bps, 16-bit samples
#define SAMPLE_LENGTH(freq) (((freq)*10)/1000)
// These are restrictions from the webrtc.org code
#define MAX_CHANNELS 2
@ -345,7 +344,7 @@ MediaEngineWebRTCMicrophoneSource::Start(SourceMediaStream *aStream,
}
AudioSegment* segment = new AudioSegment();
aStream->AddAudioTrack(aID, SAMPLE_FREQUENCY, 0, segment, SourceMediaStream::ADDTRACK_QUEUED);
aStream->AddAudioTrack(aID, mSampleFrequency, 0, segment, SourceMediaStream::ADDTRACK_QUEUED);
// XXX Make this based on the pref.
aStream->RegisterForAudioMixing();
@ -470,6 +469,9 @@ MediaEngineWebRTCMicrophoneSource::Init()
return;
}
mSampleFrequency = MediaEngine::DEFAULT_SAMPLE_RATE;
LOG(("%s: sampling rate %u", __FUNCTION__, mSampleFrequency));
// Check for availability.
ScopedCustomReleasePtr<webrtc::VoEHardware> ptrVoEHw(webrtc::VoEHardware::GetInterface(mVoiceEngine));
if (!ptrVoEHw || ptrVoEHw->SetRecordingDevice(mCapIndex)) {
@ -495,9 +497,10 @@ MediaEngineWebRTCMicrophoneSource::Init()
webrtc::CodecInst codec;
strcpy(codec.plname, ENCODING);
codec.channels = CHANNELS;
codec.rate = SAMPLE_RATE;
codec.plfreq = SAMPLE_FREQUENCY;
codec.pacsize = SAMPLE_LENGTH;
MOZ_ASSERT(mSampleFrequency == 16000 || mSampleFrequency == 32000);
codec.rate = SAMPLE_RATE(mSampleFrequency);
codec.plfreq = mSampleFrequency;
codec.pacsize = SAMPLE_LENGTH(mSampleFrequency);
codec.pltype = 0; // Default payload type
if (!ptrVoECodec->SetSendCodec(mChannel, codec)) {

View File

@ -15,7 +15,6 @@
*/
#include "GonkGPSGeolocationProvider.h"
#include "mozstumbler/MozStumbler.h"
#include <pthread.h>
#include <hardware/gps.h>
@ -40,6 +39,7 @@
#include "mozilla/dom/SettingChangeNotificationBinding.h"
#ifdef MOZ_B2G_RIL
#include "mozstumbler/MozStumbler.h"
#include "nsIIccInfo.h"
#include "nsIMobileConnectionInfo.h"
#include "nsIMobileConnectionService.h"
@ -148,7 +148,9 @@ GonkGPSGeolocationProvider::LocationCallback(GpsLocation* location)
nsRefPtr<UpdateLocationEvent> event = new UpdateLocationEvent(somewhere);
NS_DispatchToMainThread(event);
#ifdef MOZ_B2G_RIL
MozStumble(somewhere);
#endif
}
void

View File

@ -35,7 +35,6 @@ XPIDL_MODULE = 'dom_system_gonk'
EXPORTS += [
'GeolocationUtil.h',
'GonkGPSGeolocationProvider.h',
'mozstumbler/MozStumbler.h',
'nsVolume.h',
'nsVolumeService.h',
]
@ -49,10 +48,6 @@ UNIFIED_SOURCES += [
'MozMtpDatabase.cpp',
'MozMtpServer.cpp',
'MozMtpStorage.cpp',
'mozstumbler/MozStumbler.cpp',
'mozstumbler/StumblerLogging.cpp',
'mozstumbler/UploadStumbleRunnable.cpp',
'mozstumbler/WriteStumbleOnThread.cpp',
'NetIdManager.cpp',
'NetworkUtils.cpp',
'NetworkWorker.cpp',
@ -93,6 +88,15 @@ EXTRA_JS_MODULES += [
]
if CONFIG['MOZ_B2G_RIL']:
EXPORTS += [
'mozstumbler/MozStumbler.h',
]
UNIFIED_SOURCES += [
'mozstumbler/MozStumbler.cpp',
'mozstumbler/StumblerLogging.cpp',
'mozstumbler/UploadStumbleRunnable.cpp',
'mozstumbler/WriteStumbleOnThread.cpp'
]
XPIDL_SOURCES += [
'nsIDataCallInterfaceService.idl',
'nsIDataCallManager.idl',

View File

@ -3531,7 +3531,7 @@ nsHTMLEditor::SelectAll()
nsCOMPtr<nsIDOMNode> rootElement = do_QueryInterface(rootContent, &rv);
NS_ENSURE_SUCCESS(rv, rv);
Maybe<mozilla::dom::Selection::AutoApplyUserSelectStyle> userSelection;
Maybe<mozilla::dom::Selection::AutoUserInitiated> userSelection;
if (!rootContent->IsEditable()) {
userSelection.emplace(selection);
}

View File

@ -11,6 +11,7 @@
#define MOZILLA_GENERICREFCOUNTED_H_
#include "mozilla/RefPtr.h"
#include "mozilla/RefCounted.h"
namespace mozilla {

View File

@ -10,6 +10,7 @@
#include "base/message_loop.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Vector.h"
#include "FrameMetrics.h"
#include "nsISupportsImpl.h"

View File

@ -6,6 +6,10 @@
#include "WheelScrollAnimation.h"
#include "AsyncPanZoomController.h"
#include "gfxPrefs.h"
#include "nsPoint.h"
namespace mozilla {
namespace layers {

View File

@ -13,6 +13,8 @@
namespace mozilla {
namespace layers {
class AsyncPanZoomController;
class WheelScrollAnimation
: public AsyncPanZoomAnimation,
public AsyncScrollBase

View File

@ -6,6 +6,7 @@
#include "TextureHost.h"
#include "CompositableHost.h" // for CompositableHost
#include "LayerScope.h"
#include "LayersLogging.h" // for AppendToString
#include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory
#include "mozilla/ipc/Shmem.h" // for Shmem
@ -23,6 +24,7 @@
#include "mozilla/unused.h"
#include <limits>
#include "../opengl/CompositorOGL.h"
#include "gfxPrefs.h"
#include "gfxUtils.h"
#ifdef MOZ_ENABLE_D3D10_LAYER

View File

@ -178,22 +178,17 @@ CompositorChild::AllocPLayerTransactionChild(const nsTArray<LayersBackend>& aBac
return c;
}
/*static*/ PLDHashOperator
CompositorChild::RemoveSharedMetricsForLayersId(const uint64_t& aKey,
nsAutoPtr<SharedFrameMetricsData>& aData,
void* aLayerTransactionChild)
{
uint64_t childId = static_cast<LayerTransactionChild*>(aLayerTransactionChild)->GetId();
if (aData->GetLayersId() == childId) {
return PLDHashOperator::PL_DHASH_REMOVE;
}
return PLDHashOperator::PL_DHASH_NEXT;
}
bool
CompositorChild::DeallocPLayerTransactionChild(PLayerTransactionChild* actor)
{
mFrameMetricsTable.Enumerate(RemoveSharedMetricsForLayersId, actor);
uint64_t childId = static_cast<LayerTransactionChild*>(actor)->GetId();
for (auto iter = mFrameMetricsTable.Iter(); !iter.Done(); iter.Next()) {
nsAutoPtr<SharedFrameMetricsData>& data = iter.Data();
if (data->GetLayersId() == childId) {
iter.Remove();
}
}
static_cast<LayerTransactionChild*>(actor)->ReleaseIPDLReference();
return true;
}

View File

@ -174,10 +174,6 @@ private:
uint32_t mAPZCId;
};
static PLDHashOperator RemoveSharedMetricsForLayersId(const uint64_t& aKey,
nsAutoPtr<SharedFrameMetricsData>& aData,
void* aLayerTransactionChild);
nsRefPtr<ClientLayerManager> mLayerManager;
// When not multi-process, hold a reference to the CompositorParent to keep it
// alive. This reference should be null in multi-process.

View File

@ -1115,22 +1115,19 @@ gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive,
// Called on each family after all fonts are added to the list;
// this will sort faces to give priority to "standard" font files
// if aUserArg is non-null (i.e. we're using it as a boolean flag)
static PLDHashOperator
static void
FinalizeFamilyMemberList(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamily,
void* aUserArg)
bool aSortFaces)
{
gfxFontFamily *family = aFamily.get();
bool sortFaces = (aUserArg != nullptr);
family->SetHasStyles(true);
if (sortFaces) {
if (aSortFaces) {
family->SortAvailableFonts();
}
family->CheckForSimpleFamily();
return PL_DHASH_NEXT;
}
void
@ -1157,8 +1154,17 @@ gfxFT2FontList::FindFonts()
// Passing null for userdata tells Finalize that it does not need
// to sort faces (because they were already sorted by chrome,
// so we just maintain the existing order)
mFontFamilies.Enumerate(FinalizeFamilyMemberList, nullptr);
mHiddenFontFamilies.Enumerate(FinalizeFamilyMemberList, nullptr);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsStringHashKey::KeyType key = iter.Key();
nsRefPtr<gfxFontFamily>& family = iter.Data();
FinalizeFamilyMemberList(key, family, /* aSortFaces */ false);
}
for (auto iter = mHiddenFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsStringHashKey::KeyType key = iter.Key();
nsRefPtr<gfxFontFamily>& family = iter.Data();
FinalizeFamilyMemberList(key, family, /* aSortFaces */ false );
}
LOG(("got font list from chrome process: %d faces in %d families "
"and %d in hidden families",
fonts.Length(), mFontFamilies.Count(),
@ -1237,8 +1243,16 @@ gfxFT2FontList::FindFonts()
// Finalize the families by sorting faces into standard order
// and marking "simple" families.
// Passing non-null userData here says that we want faces to be sorted.
mFontFamilies.Enumerate(FinalizeFamilyMemberList, this);
mHiddenFontFamilies.Enumerate(FinalizeFamilyMemberList, this);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsStringHashKey::KeyType key = iter.Key();
nsRefPtr<gfxFontFamily>& family = iter.Data();
FinalizeFamilyMemberList(key, family, /* aSortFaces */ true);
}
for (auto iter = mHiddenFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsStringHashKey::KeyType key = iter.Key();
nsRefPtr<gfxFontFamily>& family = iter.Data();
FinalizeFamilyMemberList(key, family, /* aSortFaces */ true);
}
}
void
@ -1328,39 +1342,17 @@ gfxFT2FontList::AppendFaceFromFontListEntry(const FontListEntry& aFLE,
}
}
static PLDHashOperator
AddFamilyToFontList(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamily,
void* aUserArg)
{
InfallibleTArray<FontListEntry>* fontlist =
reinterpret_cast<InfallibleTArray<FontListEntry>*>(aUserArg);
FT2FontFamily *family = static_cast<FT2FontFamily*>(aFamily.get());
family->AddFacesToFontList(fontlist, FT2FontFamily::kVisible);
return PL_DHASH_NEXT;
}
static PLDHashOperator
AddHiddenFamilyToFontList(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamily,
void* aUserArg)
{
InfallibleTArray<FontListEntry>* fontlist =
reinterpret_cast<InfallibleTArray<FontListEntry>*>(aUserArg);
FT2FontFamily *family = static_cast<FT2FontFamily*>(aFamily.get());
family->AddFacesToFontList(fontlist, FT2FontFamily::kHidden);
return PL_DHASH_NEXT;
}
void
gfxFT2FontList::GetSystemFontList(InfallibleTArray<FontListEntry>* retValue)
{
mFontFamilies.Enumerate(AddFamilyToFontList, retValue);
mHiddenFontFamilies.Enumerate(AddHiddenFamilyToFontList, retValue);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
auto family = static_cast<FT2FontFamily*>(iter.Data().get());
family->AddFacesToFontList(retValue, FT2FontFamily::kVisible);
}
for (auto iter = mHiddenFontFamilies.Iter(); !iter.Done(); iter.Next()) {
auto family = static_cast<FT2FontFamily*>(iter.Data().get());
family->AddFacesToFontList(retValue, FT2FontFamily::kHidden);
}
}
static void
@ -1377,10 +1369,9 @@ LoadSkipSpaceLookupCheck(nsTHashtable<nsStringHashKey>& aSkipSpaceLookupCheck)
}
}
static PLDHashOperator
void
PreloadAsUserFontFaces(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamily,
void* aUserArg)
nsRefPtr<gfxFontFamily>& aFamily)
{
gfxFontFamily *family = aFamily.get();
@ -1433,8 +1424,6 @@ PreloadAsUserFontFaces(nsStringHashKey::KeyType aKey,
gfxUserFontSet::UserFontCache::CacheFont(
fe, gfxUserFontSet::UserFontCache::kPersistent);
}
return PL_DHASH_NEXT;
}
nsresult
@ -1443,74 +1432,65 @@ gfxFT2FontList::InitFontList()
// reset font lists
gfxPlatformFontList::InitFontList();
mHiddenFontFamilies.Clear();
LoadSkipSpaceLookupCheck(mSkipSpaceLookupCheckFamilies);
FindFonts();
mHiddenFontFamilies.Enumerate(PreloadAsUserFontFaces, this);
for (auto iter = mHiddenFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsStringHashKey::KeyType key = iter.Key();
nsRefPtr<gfxFontFamily>& family = iter.Data();
PreloadAsUserFontFaces(key, family);
}
return NS_OK;
}
struct FullFontNameSearch {
FullFontNameSearch(const nsAString& aFullName)
: mFullName(aFullName), mFontEntry(nullptr)
{ }
nsString mFullName;
FT2FontEntry *mFontEntry;
};
// callback called for each family name, based on the assumption that the
// called for each family name, based on the assumption that the
// first part of the full name is the family name
static PLDHashOperator
FindFullName(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFontFamily,
void* userArg)
{
FullFontNameSearch *data = reinterpret_cast<FullFontNameSearch*>(userArg);
// does the family name match up to the length of the family name?
const nsString& family = aFontFamily->Name();
nsString fullNameFamily;
data->mFullName.Left(fullNameFamily, family.Length());
// if so, iterate over faces in this family to see if there is a match
if (family.Equals(fullNameFamily, nsCaseInsensitiveStringComparator())) {
nsTArray<nsRefPtr<gfxFontEntry> >& fontList = aFontFamily->GetFontList();
int index, len = fontList.Length();
for (index = 0; index < len; index++) {
gfxFontEntry* fe = fontList[index];
if (!fe) {
continue;
}
if (fe->Name().Equals(data->mFullName,
nsCaseInsensitiveStringComparator())) {
data->mFontEntry = static_cast<FT2FontEntry*>(fe);
return PL_DHASH_STOP;
}
}
}
return PL_DHASH_NEXT;
}
gfxFontEntry*
gfxFontEntry*
gfxFT2FontList::LookupLocalFont(const nsAString& aFontName,
uint16_t aWeight,
int16_t aStretch,
bool aItalic)
{
// walk over list of names
FullFontNameSearch data(aFontName);
FT2FontEntry* fontEntry = nullptr;
nsString fullName(aFontName);
// Note that we only check mFontFamilies here, not mHiddenFontFamilies;
// hence @font-face { src:local(...) } will not find hidden fonts.
mFontFamilies.Enumerate(FindFullName, &data);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
// Check family name, based on the assumption that the
// first part of the full name is the family name
nsRefPtr<gfxFontFamily>& fontFamily = iter.Data();
if (!data.mFontEntry) {
// does the family name match up to the length of the family name?
const nsString& family = fontFamily->Name();
nsString fullNameFamily;
fullName.Left(fullNameFamily, family.Length());
// if so, iterate over faces in this family to see if there is a match
if (family.Equals(fullNameFamily, nsCaseInsensitiveStringComparator())) {
nsTArray<nsRefPtr<gfxFontEntry> >& fontList = fontFamily->GetFontList();
int index, len = fontList.Length();
for (index = 0; index < len; index++) {
gfxFontEntry* fe = fontList[index];
if (!fe) {
continue;
}
if (fe->Name().Equals(fullName,
nsCaseInsensitiveStringComparator())) {
fontEntry = static_cast<FT2FontEntry*>(fe);
goto searchDone;
}
}
}
}
searchDone:
if (!fontEntry) {
return nullptr;
}
@ -1518,16 +1498,16 @@ gfxFT2FontList::LookupLocalFont(const nsAString& aFontName,
// from the userfont entry rather than the actual font.
// Ensure existence of mFTFace in the original entry
data.mFontEntry->CairoFontFace();
if (!data.mFontEntry->mFTFace) {
fontEntry->CairoFontFace();
if (!fontEntry->mFTFace) {
return nullptr;
}
FT2FontEntry* fe =
FT2FontEntry::CreateFontEntry(data.mFontEntry->mFTFace,
data.mFontEntry->mFilename.get(),
data.mFontEntry->mFTFontIndex,
data.mFontEntry->Name(), nullptr);
FT2FontEntry::CreateFontEntry(fontEntry->mFTFace,
fontEntry->mFilename.get(),
fontEntry->mFTFontIndex,
fontEntry->Name(), nullptr);
if (fe) {
fe->mItalic = aItalic;
fe->mWeight = aWeight;
@ -1569,21 +1549,15 @@ gfxFT2FontList::MakePlatformFont(const nsAString& aFontName,
aItalic, aFontData, aLength);
}
static PLDHashOperator
AppendFamily(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamily,
void* aUserArg)
{
nsTArray<nsRefPtr<gfxFontFamily> > * familyArray =
reinterpret_cast<nsTArray<nsRefPtr<gfxFontFamily>>*>(aUserArg);
familyArray->AppendElement(aFamily);
return PL_DHASH_NEXT;
}
void
gfxFT2FontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
{
mFontFamilies.Enumerate(AppendFamily, &aFamilyArray);
mHiddenFontFamilies.Enumerate(AppendFamily, &aFamilyArray);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsRefPtr<gfxFontFamily>& family = iter.Data();
aFamilyArray.AppendElement(family);
}
for (auto iter = mHiddenFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsRefPtr<gfxFontFamily>& family = iter.Data();
aFamilyArray.AppendElement(family);
}
}

View File

@ -428,7 +428,7 @@ gfxFontShaper::MergeFontFeatures(
bool aDisableLigatures,
const nsAString& aFamilyName,
bool aAddSmallCaps,
PLDHashOperator (*aHandleFeature)(const uint32_t&, uint32_t&, void*),
void (*aHandleFeature)(const uint32_t&, uint32_t&, void*),
void* aHandleFeatureData)
{
uint32_t numAlts = aStyle->alternateValues.Length();
@ -530,7 +530,9 @@ gfxFontShaper::MergeFontFeatures(
}
if (mergedFeatures.Count() != 0) {
mergedFeatures.Enumerate(aHandleFeature, aHandleFeatureData);
for (auto iter = mergedFeatures.Iter(); !iter.Done(); iter.Next()) {
aHandleFeature(iter.Key(), iter.Data(), aHandleFeatureData);
}
}
}
@ -1742,7 +1744,8 @@ gfxFont::DrawGlyphs(gfxShapedText *aShapedText,
gfxFloat& inlineCoord = aFontParams.isVerticalFont ? aPt->y : aPt->x;
if (aRunParams.spacing) {
inlineCoord += aRunParams.direction * aRunParams.spacing[0].mBefore;
inlineCoord += aRunParams.isRTL ? -aRunParams.spacing[0].mBefore
: aRunParams.spacing[0].mBefore;
}
const gfxShapedText::CompressedGlyph *glyphData =
@ -1821,7 +1824,7 @@ gfxFont::DrawGlyphs(gfxShapedText *aShapedText,
buffer, &emittedGlyphs);
}
inlineCoord += aRunParams.direction * advance;
inlineCoord += aRunParams.isRTL ? -advance : advance;
}
}
}
@ -1831,7 +1834,7 @@ gfxFont::DrawGlyphs(gfxShapedText *aShapedText,
if (i + 1 < aCount) {
space += aRunParams.spacing[i + 1].mBefore;
}
inlineCoord += aRunParams.direction * space;
inlineCoord += aRunParams.isRTL ? -space : space;
}
}
@ -1874,10 +1877,15 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
const Metrics& metrics = GetMetrics(eHorizontal);
// Get a matrix we can use to draw the (horizontally-shaped) textrun
// with 90-degree CW rotation.
gfxMatrix mat = aRunParams.context->CurrentMatrix().
Translate(p). // translate origin for rotation
Rotate(M_PI / 2.0). // turn 90deg clockwise
Translate(-p); // undo the translation
const gfxFloat
rotation = (aOrientation ==
gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT)
? -M_PI / 2.0 : M_PI / 2.0;
gfxMatrix mat =
aRunParams.context->CurrentMatrix().
Translate(p). // translate origin for rotation
Rotate(rotation). // turn 90deg CCW (sideways-left) or CW (*-right)
Translate(-p); // undo the translation
// If we're drawing rotated horizontal text for an element styled
// text-orientation:mixed, the dominant baseline will be vertical-
@ -1987,7 +1995,14 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
if (sideways) {
aRunParams.context->Restore();
*aPt = gfxPoint(origPt.x, origPt.y + (aPt->x - origPt.x));
// adjust updated aPt to account for the transform we were using
gfxFloat advance = aPt->x - origPt.x;
if (aOrientation ==
gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT) {
*aPt = gfxPoint(origPt.x, origPt.y - advance);
} else {
*aPt = gfxPoint(origPt.x, origPt.y + advance);
}
}
}

View File

@ -636,8 +636,8 @@ public:
bool aDisableLigatures,
const nsAString& aFamilyName,
bool aAddSmallCaps,
PLDHashOperator (*aHandleFeature)(const uint32_t&,
uint32_t&, void*),
void (*aHandleFeature)(const uint32_t&,
uint32_t&, void*),
void* aHandleFeatureData);
protected:
@ -965,8 +965,19 @@ public:
return (GetFlags() & gfxTextRunFactory::TEXT_IS_RTL) != 0;
}
bool IsSidewaysLeft() const {
return (GetFlags() & gfxTextRunFactory::TEXT_ORIENT_MASK) ==
gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT;
}
// Return true if the logical inline direction is reversed compared to
// normal physical coordinates (i.e. if it is leftwards or upwards)
bool IsInlineReversed() const {
return IsSidewaysLeft() != IsRightToLeft();
}
gfxFloat GetDirection() const {
return IsRightToLeft() ? -1.0f : 1.0f;
return IsInlineReversed() ? -1.0f : 1.0f;
}
bool DisableLigatures() const {

View File

@ -146,13 +146,6 @@ gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
}
static PLDHashOperator
DestroyHBSet(const uint32_t& aTag, hb_set_t*& aSet, void *aUserArg)
{
hb_set_destroy(aSet);
return PL_DHASH_NEXT;
}
gfxFontEntry::~gfxFontEntry()
{
if (mCOLR) {
@ -170,7 +163,10 @@ gfxFontEntry::~gfxFontEntry()
}
if (mFeatureInputs) {
mFeatureInputs->Enumerate(DestroyHBSet, nullptr);
for (auto iter = mFeatureInputs->Iter(); !iter.Done(); iter.Next()) {
hb_set_t*& set = iter.Data();
hb_set_destroy(set);
}
}
// By the time the entry is destroyed, all font instances that were

View File

@ -72,7 +72,7 @@ struct GrFontFeatures {
gr_feature_val *mFeatures;
};
static PLDHashOperator
static void
AddFeature(const uint32_t& aTag, uint32_t& aValue, void *aUserArg)
{
GrFontFeatures *f = static_cast<GrFontFeatures*>(aUserArg);
@ -81,7 +81,6 @@ AddFeature(const uint32_t& aTag, uint32_t& aValue, void *aUserArg)
if (fref) {
gr_fref_set_feature_value(fref, aValue, f->mFeatures);
}
return PL_DHASH_NEXT;
}
bool

View File

@ -1224,7 +1224,7 @@ HBUnicodeDecompose(hb_unicode_funcs_t *ufuncs,
#endif
}
static PLDHashOperator
static void
AddOpenTypeFeature(const uint32_t& aTag, uint32_t& aValue, void *aUserArg)
{
nsTArray<hb_feature_t>* features = static_cast<nsTArray<hb_feature_t>*> (aUserArg);
@ -1233,7 +1233,6 @@ AddOpenTypeFeature(const uint32_t& aTag, uint32_t& aValue, void *aUserArg)
feat.tag = aTag;
feat.value = aValue;
features->AppendElement(feat);
return PL_DHASH_NEXT;
}
/*

View File

@ -237,18 +237,9 @@ gfxPlatformFontList::GenerateFontListKey(const nsAString& aKeyName, nsAString& a
ToLowerCase(aResult);
}
struct InitOtherNamesData {
InitOtherNamesData(gfxPlatformFontList *aFontList,
TimeStamp aStartTime)
: mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false)
{}
#define OTHERNAMES_TIMEOUT 200
gfxPlatformFontList *mFontList;
TimeStamp mStartTime;
bool mTimedOut;
};
void
void
gfxPlatformFontList::InitOtherFamilyNames()
{
if (mOtherFamilyNamesInitialized) {
@ -256,14 +247,19 @@ gfxPlatformFontList::InitOtherFamilyNames()
}
TimeStamp start = TimeStamp::Now();
bool timedOut = false;
// iterate over all font families and read in other family names
InitOtherNamesData otherNamesData(this, start);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsRefPtr<gfxFontFamily>& family = iter.Data();
family->ReadOtherFamilyNames(this);
TimeDuration elapsed = TimeStamp::Now() - start;
if (elapsed.ToMilliseconds() > OTHERNAMES_TIMEOUT) {
timedOut = true;
break;
}
}
mFontFamilies.Enumerate(gfxPlatformFontList::InitOtherFamilyNamesProc,
&otherNamesData);
if (!otherNamesData.mTimedOut) {
if (!timedOut) {
mOtherFamilyNamesInitialized = true;
}
TimeStamp end = TimeStamp::Now();
@ -274,55 +270,44 @@ gfxPlatformFontList::InitOtherFamilyNames()
TimeDuration elapsed = end - start;
LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms %s",
elapsed.ToMilliseconds(),
(otherNamesData.mTimedOut ? "timeout" : "")));
(timedOut ? "timeout" : "")));
}
}
#define OTHERNAMES_TIMEOUT 200
PLDHashOperator
gfxPlatformFontList::InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void* userArg)
{
InitOtherNamesData *data = static_cast<InitOtherNamesData*>(userArg);
aFamilyEntry->ReadOtherFamilyNames(data->mFontList);
TimeDuration elapsed = TimeStamp::Now() - data->mStartTime;
if (elapsed.ToMilliseconds() > OTHERNAMES_TIMEOUT) {
data->mTimedOut = true;
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
struct ReadFaceNamesData {
ReadFaceNamesData(gfxPlatformFontList *aFontList, TimeStamp aStartTime)
: mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false),
mFirstChar(0)
{}
gfxPlatformFontList *mFontList;
TimeStamp mStartTime;
bool mTimedOut;
// if mFirstChar is not 0, only load facenames for families
// that start with this character
char16_t mFirstChar;
};
// time limit for loading facename lists (ms)
#define NAMELIST_TIMEOUT 200
gfxFontEntry*
gfxPlatformFontList::SearchFamiliesForFaceName(const nsAString& aFaceName)
{
TimeStamp start = TimeStamp::Now();
bool timedOut = false;
// if mFirstChar is not 0, only load facenames for families
// that start with this character
char16_t firstChar = 0;
gfxFontEntry *lookup = nullptr;
ReadFaceNamesData faceNameListsData(this, start);
// iterate over familes starting with the same letter
faceNameListsData.mFirstChar = ToLowerCase(aFaceName.CharAt(0));
mFontFamilies.Enumerate(gfxPlatformFontList::ReadFaceNamesProc,
&faceNameListsData);
firstChar = ToLowerCase(aFaceName.CharAt(0));
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsStringHashKey::KeyType key = iter.Key();
nsRefPtr<gfxFontFamily>& family = iter.Data();
// when filtering, skip names that don't start with the filter character
if (firstChar && ToLowerCase(key.CharAt(0)) != firstChar) {
continue;
}
family->ReadFaceNames(this, NeedFullnamePostscriptNames());
TimeDuration elapsed = TimeStamp::Now() - start;
if (elapsed.ToMilliseconds() > NAMELIST_TIMEOUT) {
timedOut = true;
break;
}
}
lookup = FindFaceName(aFaceName);
TimeStamp end = TimeStamp::Now();
@ -333,38 +318,12 @@ gfxPlatformFontList::SearchFamiliesForFaceName(const nsAString& aFaceName)
LOG_FONTINIT(("(fontinit) SearchFamiliesForFaceName took %8.2f ms %s %s",
elapsed.ToMilliseconds(),
(lookup ? "found name" : ""),
(faceNameListsData.mTimedOut ? "timeout" : "")));
(timedOut ? "timeout" : "")));
}
return lookup;
}
// time limit for loading facename lists (ms)
#define NAMELIST_TIMEOUT 200
PLDHashOperator
gfxPlatformFontList::ReadFaceNamesProc(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void* userArg)
{
ReadFaceNamesData *data = static_cast<ReadFaceNamesData*>(userArg);
gfxPlatformFontList *fc = data->mFontList;
// when filtering, skip names that don't start with the filter character
if (data->mFirstChar && ToLowerCase(aKey.CharAt(0)) != data->mFirstChar) {
return PL_DHASH_NEXT;
}
aFamilyEntry->ReadFaceNames(fc, fc->NeedFullnamePostscriptNames());
TimeDuration elapsed = TimeStamp::Now() - data->mStartTime;
if (elapsed.ToMilliseconds() > NAMELIST_TIMEOUT) {
data->mTimedOut = true;
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
gfxFontEntry*
gfxPlatformFontList::FindFaceName(const nsAString& aFaceName)
{
@ -449,84 +408,49 @@ gfxPlatformFontList::UpdateFontList()
RebuildLocalFonts();
}
struct FontListData {
FontListData(nsIAtom *aLangGroup,
const nsACString& aGenericFamily,
nsTArray<nsString>& aListOfFonts) :
mLangGroup(aLangGroup), mGenericFamily(aGenericFamily),
mListOfFonts(aListOfFonts) {}
nsIAtom *mLangGroup;
const nsACString& mGenericFamily;
nsTArray<nsString>& mListOfFonts;
};
PLDHashOperator
gfxPlatformFontList::HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void *aUserArg)
{
FontListData *data = static_cast<FontListData*>(aUserArg);
// use the first variation for now. This data should be the same
// for all the variations and should probably be moved up to
// the Family
gfxFontStyle style;
style.language = data->mLangGroup;
bool needsBold;
nsRefPtr<gfxFontEntry> aFontEntry = aFamilyEntry->FindFontForStyle(style, needsBold);
NS_ASSERTION(aFontEntry, "couldn't find any font entry in family");
if (!aFontEntry)
return PL_DHASH_NEXT;
/* skip symbol fonts */
if (aFontEntry->IsSymbolFont())
return PL_DHASH_NEXT;
if (aFontEntry->SupportsLangGroup(data->mLangGroup) &&
aFontEntry->MatchesGenericFamily(data->mGenericFamily)) {
nsAutoString localizedFamilyName;
aFamilyEntry->LocalizedName(localizedFamilyName);
data->mListOfFonts.AppendElement(localizedFamilyName);
}
return PL_DHASH_NEXT;
}
void
gfxPlatformFontList::GetFontList(nsIAtom *aLangGroup,
const nsACString& aGenericFamily,
nsTArray<nsString>& aListOfFonts)
{
FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsRefPtr<gfxFontFamily>& family = iter.Data();
// use the first variation for now. This data should be the same
// for all the variations and should probably be moved up to
// the Family
gfxFontStyle style;
style.language = aLangGroup;
bool needsBold;
nsRefPtr<gfxFontEntry> fontEntry = family->FindFontForStyle(style, needsBold);
NS_ASSERTION(fontEntry, "couldn't find any font entry in family");
if (!fontEntry) {
continue;
}
mFontFamilies.Enumerate(gfxPlatformFontList::HashEnumFuncForFamilies, &data);
/* skip symbol fonts */
if (fontEntry->IsSymbolFont()) {
continue;
}
if (fontEntry->SupportsLangGroup(aLangGroup) &&
fontEntry->MatchesGenericFamily(aGenericFamily)) {
nsAutoString localizedFamilyName;
family->LocalizedName(localizedFamilyName);
aListOfFonts.AppendElement(localizedFamilyName);
}
}
aListOfFonts.Sort();
aListOfFonts.Compact();
}
struct FontFamilyListData {
explicit FontFamilyListData(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
: mFamilyArray(aFamilyArray)
{}
static PLDHashOperator AppendFamily(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void *aUserArg)
{
FontFamilyListData *data = static_cast<FontFamilyListData*>(aUserArg);
data->mFamilyArray.AppendElement(aFamilyEntry);
return PL_DHASH_NEXT;
}
nsTArray<nsRefPtr<gfxFontFamily> >& mFamilyArray;
};
void
gfxPlatformFontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
{
FontFamilyListData data(aFamilyArray);
mFontFamilies.Enumerate(FontFamilyListData::AppendFamily, &data);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsRefPtr<gfxFontFamily>& family = iter.Data();
aFamilyArray.AppendElement(family);
}
}
gfxFontEntry*
@ -616,18 +540,6 @@ gfxPlatformFontList::SystemFindFontForChar(uint32_t aCh, uint32_t aNextCh,
return fontEntry;
}
PLDHashOperator
gfxPlatformFontList::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr<gfxFontFamily>& aFamilyEntry,
void *userArg)
{
GlobalFontMatch *data = static_cast<GlobalFontMatch*>(userArg);
// evaluate all fonts in this family for a match
aFamilyEntry->FindFontForChar(data);
return PL_DHASH_NEXT;
}
#define NUM_FALLBACK_FONTS 8
gfxFontEntry*
@ -677,7 +589,11 @@ gfxPlatformFontList::GlobalFontFallback(const uint32_t aCh,
GlobalFontMatch data(aCh, aRunScript, aMatchStyle);
// iterate over all font families to find a font that support the character
mFontFamilies.Enumerate(gfxPlatformFontList::FindFontForCharProc, &data);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsRefPtr<gfxFontFamily>& family = iter.Data();
// evaluate all fonts in this family for a match
family->FindFontForChar(&data);
}
aCmapCount = data.mCmapsTested;
*aMatchedFamily = data.mMatchedFamily;
@ -885,22 +801,16 @@ gfxPlatformFontList::RemoveCmap(const gfxCharacterMap* aCharMap)
}
}
static PLDHashOperator AppendFamilyToList(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void *aUserArg)
{
nsTArray<nsString> *familyNames = static_cast<nsTArray<nsString> *>(aUserArg);
familyNames->AppendElement(aFamilyEntry->Name());
return PL_DHASH_NEXT;
}
void
gfxPlatformFontList::GetFontFamilyNames(nsTArray<nsString>& aFontFamilyNames)
{
mFontFamilies.Enumerate(AppendFamilyToList, &aFontFamilyNames);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsRefPtr<gfxFontFamily>& family = iter.Data();
aFontFamilyNames.AppendElement(family->Name());
}
}
void
void
gfxPlatformFontList::InitLoader()
{
GetFontFamilyNames(mFontInfo->mFontFamiliesToLoad);

View File

@ -212,10 +212,6 @@ protected:
static gfxPlatformFontList *sPlatformFontList;
static PLDHashOperator FindFontForCharProc(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void* userArg);
// Lookup family name in global family list without substitutions or
// localized family name lookup. Used for common font fallback families.
gfxFontFamily* FindFamilyByCanonicalName(const nsAString& aFamily) {
@ -251,21 +247,11 @@ protected:
// initialize localized family names
void InitOtherFamilyNames();
static PLDHashOperator
InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void* userArg);
// search through font families, looking for a given name, initializing
// facename lists along the way. first checks all families with names
// close to face name, then searchs all families if not found.
gfxFontEntry* SearchFamiliesForFaceName(const nsAString& aFaceName);
static PLDHashOperator
ReadFaceNamesProc(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void* userArg);
// helper method for finding fullname/postscript names in facename lists
gfxFontEntry* FindFaceName(const nsAString& aFaceName);

View File

@ -811,14 +811,14 @@ RasterImage::OnAddedFrame(uint32_t aNewFrameCount,
}
}
void
bool
RasterImage::SetMetadata(const ImageMetadata& aMetadata,
bool aFromMetadataDecode)
{
MOZ_ASSERT(NS_IsMainThread());
if (mError) {
return;
return true;
}
if (aMetadata.HasSize()) {
@ -826,7 +826,7 @@ RasterImage::SetMetadata(const ImageMetadata& aMetadata,
if (size.width < 0 || size.height < 0) {
NS_WARNING("Image has negative intrinsic size");
DoError();
return;
return true;
}
MOZ_ASSERT(aMetadata.HasOrientation());
@ -837,7 +837,7 @@ RasterImage::SetMetadata(const ImageMetadata& aMetadata,
NS_WARNING("Image changed size or orientation on redecode! "
"This should not happen!");
DoError();
return;
return true;
}
// Set the size and flag that we have it.
@ -859,7 +859,7 @@ RasterImage::SetMetadata(const ImageMetadata& aMetadata,
// discovered that it actually was during the full decode. This is a
// rare failure that only occurs for corrupt images. To recover, we need
// to discard all existing surfaces and redecode.
RecoverFromInvalidFrames(mSize, DECODE_FLAGS_DEFAULT);
return false;
}
}
@ -881,6 +881,8 @@ RasterImage::SetMetadata(const ImageMetadata& aMetadata,
Set("hotspotX", intwrapx);
Set("hotspotY", intwrapy);
}
return true;
}
NS_IMETHODIMP
@ -1732,7 +1734,18 @@ RasterImage::FinalizeDecoder(Decoder* aDecoder)
}
// Record all the metadata the decoder gathered about this image.
SetMetadata(aDecoder->GetImageMetadata(), wasMetadata);
bool metadataOK = SetMetadata(aDecoder->GetImageMetadata(), wasMetadata);
if (!metadataOK) {
// This indicates a serious error that requires us to discard all existing
// surfaces and redecode to recover. We'll drop the results from this
// decoder on the floor, since they aren't valid.
aDecoder->TakeProgress();
aDecoder->TakeInvalidRect();
RecoverFromInvalidFrames(mSize,
FromSurfaceFlags(aDecoder->GetSurfaceFlags()));
return;
}
MOZ_ASSERT(mError || mHasSize || !aDecoder->HasSize(),
"SetMetadata should've gotten a size");

View File

@ -324,8 +324,11 @@ private:
* @param aMetadata The metadata to set on this image.
* @param aFromMetadataDecode True if this metadata came from a metadata
* decode; false if it came from a full decode.
* @return |true| unless a catastrophic failure was discovered. If |false| is
* returned, it indicates that the image is corrupt in a way that requires all
* surfaces to be discarded to recover.
*/
void SetMetadata(const ImageMetadata& aMetadata, bool aFromMetadataDecode);
bool SetMetadata(const ImageMetadata& aMetadata, bool aFromMetadataDecode);
/**
* In catastrophic circumstances like a GPU driver crash, the contents of our

View File

@ -17,6 +17,7 @@
#include "mozilla/Move.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/RefPtr.h"
#include "mozilla/RefCounted.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/nsRefPtr.h"
#include "nsTArray.h"

View File

@ -50,6 +50,23 @@ ToSurfaceFlags(uint32_t aFlags)
return flags;
}
/**
* Given a set of SurfaceFlags, returns a set of imgIContainer FLAG_* flags with
* the corresponding flags set.
*/
inline uint32_t
FromSurfaceFlags(SurfaceFlags aFlags)
{
uint32_t flags = imgIContainer::DECODE_FLAGS_DEFAULT;
if (aFlags & SurfaceFlags::NO_PREMULTIPLY_ALPHA) {
flags |= imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
}
if (aFlags & SurfaceFlags::NO_COLORSPACE_CONVERSION) {
flags |= imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION;
}
return flags;
}
} // namespace image
} // namespace mozilla

View File

@ -497,14 +497,23 @@ NS_IMETHODIMP
VectorImage::GetWidth(int32_t* aWidth)
{
if (mError || !mIsFullyLoaded) {
*aWidth = -1;
} else {
SVGSVGElement* rootElem = mSVGDocumentWrapper->GetRootSVGElem();
MOZ_ASSERT(rootElem, "Should have a root SVG elem, since we finished "
"loading without errors");
*aWidth = rootElem->GetIntrinsicWidth();
// XXXdholbert Technically we should leave outparam untouched when we
// fail. But since many callers don't check for failure, we set it to 0 on
// failure, for sane/predictable results.
*aWidth = 0;
return NS_ERROR_FAILURE;
}
return *aWidth >= 0 ? NS_OK : NS_ERROR_FAILURE;
SVGSVGElement* rootElem = mSVGDocumentWrapper->GetRootSVGElem();
MOZ_ASSERT(rootElem, "Should have a root SVG elem, since we finished "
"loading without errors");
int32_t rootElemWidth = rootElem->GetIntrinsicWidth();
if (rootElemWidth < 0) {
*aWidth = 0;
return NS_ERROR_FAILURE;
}
*aWidth = rootElemWidth;
return NS_OK;
}
//******************************************************************************
@ -561,14 +570,23 @@ NS_IMETHODIMP
VectorImage::GetHeight(int32_t* aHeight)
{
if (mError || !mIsFullyLoaded) {
*aHeight = -1;
} else {
SVGSVGElement* rootElem = mSVGDocumentWrapper->GetRootSVGElem();
MOZ_ASSERT(rootElem, "Should have a root SVG elem, since we finished "
"loading without errors");
*aHeight = rootElem->GetIntrinsicHeight();
// XXXdholbert Technically we should leave outparam untouched when we
// fail. But since many callers don't check for failure, we set it to 0 on
// failure, for sane/predictable results.
*aHeight = 0;
return NS_ERROR_FAILURE;
}
return *aHeight >= 0 ? NS_OK : NS_ERROR_FAILURE;
SVGSVGElement* rootElem = mSVGDocumentWrapper->GetRootSVGElem();
MOZ_ASSERT(rootElem, "Should have a root SVG elem, since we finished "
"loading without errors");
int32_t rootElemHeight = rootElem->GetIntrinsicHeight();
if (rootElemHeight < 0) {
*aHeight = 0;
return NS_ERROR_FAILURE;
}
*aHeight = rootElemHeight;
return NS_OK;
}
//******************************************************************************

View File

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html class="reftest-wait">
<body>
</body>
<script>
function createImage(loadHandler) {
var newImage = new Image;
newImage.id = "thepreviewimage";
newImage.setAttribute("src", "unsized-svg.svg");
if (loadHandler) {
newImage.onload = loadHandler;
}
// Query width & height, and display them in document:
physWidth = newImage.width;
physHeight = newImage.height;
document.documentElement.innerHTML +=
physWidth + " x " + physHeight + "<br>";
}
function part2() {
// Load image again:
createImage();
// End the crashtest.
document.documentElement.removeAttribute("class");
}
function startTest() {
// Trigger image load, and call part2() when it's loaded:
createImage(part2);
}
startTest();
</script>
</html>

View File

@ -53,6 +53,8 @@ load invalid-disposal-method-1.gif
load invalid-disposal-method-2.gif
load invalid-disposal-method-3.gif
load 1205923-1.html
# Ensure we handle ICO directory entries which specify the wrong size for the
# contained resource.
load invalid_ico_height.ico

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg"></svg>

After

Width:  |  Height:  |  Size: 47 B

View File

@ -32,7 +32,6 @@ ChildThread::~ChildThread() {
bool ChildThread::Run() {
bool r = StartWithOptions(options_);
#ifdef MOZ_NUWA_PROCESS
NS_ASSERTION(NuwaMarkCurrentThread, "NuwaMarkCurrentThread is not defined!");
if (IsNuwaProcess()) {
message_loop()->PostTask(FROM_HERE,
NewRunnableFunction(&ChildThread::MarkThread));

View File

@ -3889,13 +3889,8 @@ BytecodeEmitter::emitDestructuringOpsArrayHelper(ParseNode* pattern, VarEmitOpti
if (elem->isKind(PNK_SPREAD)) {
/* Create a new array with the rest of the iterator */
ptrdiff_t off;
if (!emitN(JSOP_NEWARRAY, 3, &off)) // ... OBJ? ITER ARRAY
if (!emitUint32Operand(JSOP_NEWARRAY, 0)) // ... OBJ? ITER ARRAY
return false;
checkTypeSet(JSOP_NEWARRAY);
jsbytecode* pc = code(off);
SET_UINT24(pc, 0);
if (!emitNumberOp(0)) // ... OBJ? ITER ARRAY INDEX
return false;
if (!emitSpread()) // ... OBJ? ARRAY INDEX
@ -7214,29 +7209,35 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op)
*/
MOZ_ASSERT(op == JSOP_NEWARRAY || op == JSOP_SPREADCALLARRAY);
int32_t nspread = 0;
uint32_t nspread = 0;
for (ParseNode* elt = pn; elt; elt = elt->pn_next) {
if (elt->isKind(PNK_SPREAD))
nspread++;
}
ptrdiff_t off;
if (!emitN(op, 3, &off)) // ARRAY
return false;
checkTypeSet(op);
jsbytecode* pc = code(off);
// Array literal's length is limited to NELEMENTS_LIMIT in parser.
static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT <= INT32_MAX,
"array literals' maximum length must not exceed limits "
"required by BaselineCompiler::emit_JSOP_NEWARRAY, "
"BaselineCompiler::emit_JSOP_INITELEM_ARRAY, "
"and DoSetElemFallback's handling of JSOP_INITELEM_ARRAY");
MOZ_ASSERT(count >= nspread);
MOZ_ASSERT(count <= NativeObject::MAX_DENSE_ELEMENTS_COUNT,
"the parser must throw an error if the array exceeds maximum "
"length");
// For arrays with spread, this is a very pessimistic allocation, the
// minimum possible final size.
SET_UINT24(pc, count - nspread);
if (!emitUint32Operand(op, count - nspread)) // ARRAY
return false;
ParseNode* pn2 = pn;
jsatomid atomIndex;
uint32_t index;
bool afterSpread = false;
for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) {
for (index = 0; pn2; index++, pn2 = pn2->pn_next) {
if (!afterSpread && pn2->isKind(PNK_SPREAD)) {
afterSpread = true;
if (!emitNumberOp(atomIndex)) // ARRAY INDEX
if (!emitNumberOp(index)) // ARRAY INDEX
return false;
}
if (!updateSourceCoordNotes(pn2->pn_pos.begin))
@ -7262,12 +7263,11 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op)
if (!emit1(JSOP_INITELEM_INC))
return false;
} else {
if (!emitN(JSOP_INITELEM_ARRAY, 3, &off))
if (!emitUint32Operand(JSOP_INITELEM_ARRAY, index))
return false;
SET_UINT24(code(off), atomIndex);
}
}
MOZ_ASSERT(atomIndex == count);
MOZ_ASSERT(index == count);
if (afterSpread) {
if (!emit1(JSOP_POP)) // ARRAY
return false;

View File

@ -8767,7 +8767,7 @@ Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling)
uint32_t index = 0;
TokenStream::Modifier modifier = TokenStream::Operand;
for (; ; index++) {
if (index == NativeObject::NELEMENTS_LIMIT) {
if (index >= NativeObject::MAX_DENSE_ELEMENTS_COUNT) {
report(ParseError, false, null(), JSMSG_ARRAY_INIT_TOO_BIG);
return null();
}

View File

@ -0,0 +1,40 @@
// |jit-test| allow-oom
// Appending elements to a dense array should make the array sparse when the
// length exceeds the limit.
function test() {
const MAX_DENSE_ELEMENTS_ALLOCATION = (1 << 28) - 1;
const VALUES_PER_HEADER = 2;
const MAX_DENSE_ELEMENTS_COUNT = MAX_DENSE_ELEMENTS_ALLOCATION - VALUES_PER_HEADER;
const SPARSE_DENSITY_RATIO = 8;
const MIN_DENSE = MAX_DENSE_ELEMENTS_COUNT / SPARSE_DENSITY_RATIO;
const MARGIN = 16;
let a = [];
// Fill the beginning of array to make it keep dense until length exceeds
// MAX_DENSE_ELEMENTS_COUNT.
for (let i = 0; i < MIN_DENSE; i++)
a[i] = i;
// Skip from MIN_DENSE to MAX_DENSE_ELEMENTS_COUNT - MARGIN, to reduce the
// time taken by test.
// Fill the ending of array to make it sparse at MAX_DENSE_ELEMENTS_COUNT.
for (let i = MAX_DENSE_ELEMENTS_COUNT - MARGIN; i < MAX_DENSE_ELEMENTS_COUNT + MARGIN; i++)
a[i] = i;
// Make sure the last element is defined.
assertEq(a.length, MAX_DENSE_ELEMENTS_COUNT + MARGIN);
assertEq(a[a.length - 1], MAX_DENSE_ELEMENTS_COUNT + MARGIN - 1);
// Make sure elements around MAX_DENSE_ELEMENTS_COUNT are also defined.
assertEq(a[MAX_DENSE_ELEMENTS_COUNT - 1], MAX_DENSE_ELEMENTS_COUNT - 1);
assertEq(a[MAX_DENSE_ELEMENTS_COUNT], MAX_DENSE_ELEMENTS_COUNT);
assertEq(a[MAX_DENSE_ELEMENTS_COUNT + 1], MAX_DENSE_ELEMENTS_COUNT + 1);
}
var config = getBuildConfiguration();
// Takes too long time on debug build.
if (!config.debug) {
test();
}

View File

@ -6,6 +6,7 @@
#include "jit/BaselineCompiler.h"
#include "mozilla/Casting.h"
#include "mozilla/UniquePtr.h"
#include "jit/BaselineIC.h"
@ -32,6 +33,8 @@
using namespace js;
using namespace js::jit;
using mozilla::AssertedCast;
BaselineCompiler::BaselineCompiler(JSContext* cx, TempAllocator& alloc, JSScript* script)
: BaselineCompilerSpecific(cx, alloc, script),
yieldOffsets_(cx),
@ -1792,10 +1795,13 @@ BaselineCompiler::emit_JSOP_NEWARRAY()
{
frame.syncStack(0);
uint32_t length = GET_UINT24(pc);
uint32_t length = GET_UINT32(pc);
MOZ_ASSERT(length <= INT32_MAX,
"the bytecode emitter must fail to compile code that would "
"produce JSOP_NEWARRAY with a length exceeding int32_t range");
// Pass length in R0.
masm.move32(Imm32(length), R0.scratchReg());
masm.move32(Imm32(AssertedCast<int32_t>(length)), R0.scratchReg());
ObjectGroup* group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
if (!group)
@ -1849,7 +1855,12 @@ BaselineCompiler::emit_JSOP_INITELEM_ARRAY()
// Load object in R0, index in R1.
masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
masm.moveValue(Int32Value(GET_UINT24(pc)), R1);
uint32_t index = GET_UINT32(pc);
MOZ_ASSERT(index <= INT32_MAX,
"the bytecode emitter must fail to compile code that would "
"produce JSOP_INITELEM_ARRAY with a length exceeding "
"int32_t range");
masm.moveValue(Int32Value(AssertedCast<int32_t>(index)), R1);
// Call IC.
ICSetElem_Fallback::Compiler stubCompiler(cx);

View File

@ -3689,7 +3689,11 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
if (!InitElemOperation(cx, obj, index, rhs))
return false;
} else if (op == JSOP_INITELEM_ARRAY) {
MOZ_ASSERT(uint32_t(index.toInt32()) == GET_UINT24(pc));
MOZ_ASSERT(uint32_t(index.toInt32()) <= INT32_MAX,
"the bytecode emitter must fail to compile code that would "
"produce JSOP_INITELEM_ARRAY with an index exceeding "
"int32_t range");
MOZ_ASSERT(uint32_t(index.toInt32()) == GET_UINT32(pc));
if (!InitArrayElemOperation(cx, pc, obj, index.toInt32(), rhs))
return false;
} else if (op == JSOP_INITELEM_INC) {

View File

@ -4220,12 +4220,12 @@ CodeGenerator::visitNewArrayCallVM(LNewArray* lir)
if (templateObject) {
pushArg(Imm32(lir->mir()->convertDoubleElements()));
pushArg(ImmGCPtr(templateObject->group()));
pushArg(Imm32(lir->mir()->count()));
pushArg(Imm32(lir->mir()->length()));
callVM(NewArrayWithGroupInfo, lir);
} else {
pushArg(Imm32(GenericObject));
pushArg(Imm32(lir->mir()->count()));
pushArg(Imm32(lir->mir()->length()));
pushArg(ImmPtr(lir->mir()->pc()));
pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
@ -4301,9 +4301,9 @@ CodeGenerator::visitNewArray(LNewArray* lir)
Register objReg = ToRegister(lir->output());
Register tempReg = ToRegister(lir->temp());
JSObject* templateObject = lir->mir()->templateObject();
DebugOnly<uint32_t> count = lir->mir()->count();
DebugOnly<uint32_t> length = lir->mir()->length();
MOZ_ASSERT(count < NativeObject::NELEMENTS_LIMIT);
MOZ_ASSERT(length <= NativeObject::MAX_DENSE_ELEMENTS_COUNT);
if (lir->mir()->shouldUseVM()) {
visitNewArrayCallVM(lir);
@ -6946,7 +6946,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
key, &callStub);
// Update initialized length. The capacity guard above ensures this won't overflow,
// due to NELEMENTS_LIMIT.
// due to MAX_DENSE_ELEMENTS_COUNT.
masm.bumpKey(&key, 1);
masm.storeKey(key, Address(elements, ObjectElements::offsetOfInitializedLength()));

View File

@ -1794,7 +1794,7 @@ IonBuilder::inspectOpcode(JSOp op)
return jsop_newobject();
case JSOP_NEWARRAY:
return jsop_newarray(GET_UINT24(pc));
return jsop_newarray(GET_UINT32(pc));
case JSOP_NEWARRAY_COPYONWRITE:
return jsop_newarray_copyonwrite();
@ -6925,7 +6925,7 @@ IonBuilder::compareTrySharedStub(bool* emitted, JSOp op, MDefinition* left, MDef
}
bool
IonBuilder::jsop_newarray(uint32_t count)
IonBuilder::jsop_newarray(uint32_t length)
{
JSObject* templateObject = inspector->getTemplateObject(pc);
gc::InitialHeap heap;
@ -6940,7 +6940,7 @@ IonBuilder::jsop_newarray(uint32_t count)
}
current->add(templateConst);
MNewArray* ins = MNewArray::New(alloc(), constraints(), count, templateConst, heap, pc);
MNewArray* ins = MNewArray::New(alloc(), constraints(), length, templateConst, heap, pc);
current->add(ins);
current->push(ins);
@ -7052,13 +7052,14 @@ IonBuilder::jsop_initelem_array()
}
}
uint32_t index = GET_UINT32(pc);
if (needStub) {
MCallInitElementArray* store = MCallInitElementArray::New(alloc(), obj, GET_UINT24(pc), value);
MCallInitElementArray* store = MCallInitElementArray::New(alloc(), obj, index, value);
current->add(store);
return resumeAfter(store);
}
return initializeArrayElement(obj, GET_UINT24(pc), value, unboxedType, /* addResumePoint = */ true);
return initializeArrayElement(obj, index, value, unboxedType, /* addResumePoint = */ true);
}
bool

View File

@ -696,7 +696,7 @@ class IonBuilder
bool jsop_setprop(PropertyName* name);
bool jsop_delprop(PropertyName* name);
bool jsop_delelem();
bool jsop_newarray(uint32_t count);
bool jsop_newarray(uint32_t length);
bool jsop_newarray_copyonwrite();
bool jsop_newobject();
bool jsop_initelem();

View File

@ -442,8 +442,9 @@ IonBuilder::inlineArray(CallInfo& callInfo)
// Negative lengths generate a RangeError, unhandled by the inline path.
initLength = arg->constantValue().toInt32();
if (initLength >= NativeObject::NELEMENTS_LIMIT)
if (initLength > NativeObject::MAX_DENSE_ELEMENTS_COUNT)
return InliningStatus_NotInlined;
MOZ_ASSERT(initLength <= INT32_MAX);
// Make sure initLength matches the template object's length. This is
// not guaranteed to be the case, for instance if we're inlining the

View File

@ -4050,7 +4050,7 @@ MArrayState::MArrayState(MDefinition* arr)
// This instruction is only used as a summary for bailout paths.
setResultType(MIRType_Object);
setRecoveredOnBailout();
numElements_ = arr->toNewArray()->count();
numElements_ = arr->toNewArray()->length();
}
bool
@ -4090,10 +4090,10 @@ MArrayState::Copy(TempAllocator& alloc, MArrayState* state)
return res;
}
MNewArray::MNewArray(CompilerConstraintList* constraints, uint32_t count, MConstant* templateConst,
MNewArray::MNewArray(CompilerConstraintList* constraints, uint32_t length, MConstant* templateConst,
gc::InitialHeap initialHeap, jsbytecode* pc)
: MUnaryInstruction(templateConst),
count_(count),
length_(length),
initialHeap_(initialHeap),
convertDoubleElements_(false),
pc_(pc)
@ -4115,16 +4115,16 @@ MNewArray::shouldUseVM() const
return true;
if (templateObject()->is<UnboxedArrayObject>()) {
MOZ_ASSERT(templateObject()->as<UnboxedArrayObject>().capacity() >= count());
MOZ_ASSERT(templateObject()->as<UnboxedArrayObject>().capacity() >= length());
return !templateObject()->as<UnboxedArrayObject>().hasInlineElements();
}
MOZ_ASSERT(count() < NativeObject::NELEMENTS_LIMIT);
MOZ_ASSERT(length() <= NativeObject::MAX_DENSE_ELEMENTS_COUNT);
size_t arraySlots =
gc::GetGCKindSlots(templateObject()->asTenured().getAllocKind()) - ObjectElements::VALUES_PER_HEADER;
return count() > arraySlots;
return length() > arraySlots;
}
bool

View File

@ -2905,8 +2905,8 @@ class MNewArray
public NoTypePolicy::Data
{
private:
// Number of space to allocate for the array.
uint32_t count_;
// Number of elements to allocate for the array.
uint32_t length_;
// Heap where the array should be allocated.
gc::InitialHeap initialHeap_;
@ -2916,21 +2916,21 @@ class MNewArray
jsbytecode* pc_;
MNewArray(CompilerConstraintList* constraints, uint32_t count, MConstant* templateConst,
MNewArray(CompilerConstraintList* constraints, uint32_t length, MConstant* templateConst,
gc::InitialHeap initialHeap, jsbytecode* pc);
public:
INSTRUCTION_HEADER(NewArray)
static MNewArray* New(TempAllocator& alloc, CompilerConstraintList* constraints,
uint32_t count, MConstant* templateConst,
uint32_t length, MConstant* templateConst,
gc::InitialHeap initialHeap, jsbytecode* pc)
{
return new(alloc) MNewArray(constraints, count, templateConst, initialHeap, pc);
return new(alloc) MNewArray(constraints, length, templateConst, initialHeap, pc);
}
uint32_t count() const {
return count_;
uint32_t length() const {
return length_;
}
JSObject* templateObject() const {

View File

@ -1734,7 +1734,7 @@ MArrayLength::computeRange(TempAllocator& alloc)
void
MInitializedLength::computeRange(TempAllocator& alloc)
{
setRange(Range::NewUInt32Range(alloc, 0, NativeObject::NELEMENTS_LIMIT));
setRange(Range::NewUInt32Range(alloc, 0, NativeObject::MAX_DENSE_ELEMENTS_COUNT));
}
void

View File

@ -1207,7 +1207,7 @@ MNewArray::writeRecoverData(CompactBufferWriter& writer) const
{
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_NewArray));
writer.writeUnsigned(count());
writer.writeUnsigned(length());
return true;
}

View File

@ -895,7 +895,7 @@ IsArrayEscaped(MInstruction* ins)
{
MOZ_ASSERT(ins->type() == MIRType_Object);
MOZ_ASSERT(ins->isNewArray());
uint32_t count = ins->toNewArray()->count();
uint32_t length = ins->toNewArray()->length();
JitSpewDef(JitSpew_Escape, "Check array\n", ins);
JitSpewIndent spewIndent(JitSpew_Escape);
@ -911,7 +911,7 @@ IsArrayEscaped(MInstruction* ins)
return true;
}
if (count >= 16) {
if (length >= 16) {
JitSpew(JitSpew_Escape, "Array has too many elements");
return true;
}
@ -935,7 +935,7 @@ IsArrayEscaped(MInstruction* ins)
case MDefinition::Op_Elements: {
MElements *elem = def->toElements();
MOZ_ASSERT(elem->object() == ins);
if (IsElementEscaped(elem, count)) {
if (IsElementEscaped(elem, length)) {
JitSpewDef(JitSpew_Escape, "is indirectly escaped by\n", elem);
return true;
}

View File

@ -172,7 +172,7 @@ GetGCObjectKind(size_t numSlots)
/* As for GetGCObjectKind, but for dense array allocation. */
static inline AllocKind
GetGCArrayKind(size_t numSlots)
GetGCArrayKind(size_t numElements)
{
/*
* Dense arrays can use their fixed slots to hold their elements array
@ -181,9 +181,12 @@ GetGCArrayKind(size_t numSlots)
* unused.
*/
JS_STATIC_ASSERT(ObjectElements::VALUES_PER_HEADER == 2);
if (numSlots > NativeObject::NELEMENTS_LIMIT || numSlots + 2 >= SLOTS_TO_THING_KIND_LIMIT)
if (numElements > NativeObject::MAX_DENSE_ELEMENTS_COUNT ||
numElements + ObjectElements::VALUES_PER_HEADER >= SLOTS_TO_THING_KIND_LIMIT)
{
return AllocKind::OBJECT2;
return slotsToThingKind[numSlots + 2];
}
return slotsToThingKind[numElements + ObjectElements::VALUES_PER_HEADER];
}
static inline AllocKind

View File

@ -791,23 +791,23 @@ NewObjectWithGroup(ExclusiveContext* cx, HandleObjectGroup group,
}
/*
* As for gc::GetGCObjectKind, where numSlots is a guess at the final size of
* As for gc::GetGCObjectKind, where numElements is a guess at the final size of
* the object, zero if the final size is unknown. This should only be used for
* objects that do not require any fixed slots.
*/
static inline gc::AllocKind
GuessObjectGCKind(size_t numSlots)
GuessObjectGCKind(size_t numElements)
{
if (numSlots)
return gc::GetGCObjectKind(numSlots);
if (numElements)
return gc::GetGCObjectKind(numElements);
return gc::AllocKind::OBJECT4;
}
static inline gc::AllocKind
GuessArrayGCKind(size_t numSlots)
GuessArrayGCKind(size_t numElements)
{
if (numSlots)
return gc::GetGCArrayKind(numSlots);
if (numElements)
return gc::GetGCArrayKind(numElements);
return gc::AllocKind::OBJECT8;
}

View File

@ -10,29 +10,26 @@
/*
* JS Capability Macros.
*/
#define JS_HAS_STR_HTML_HELPERS 1 /* has str.anchor, str.bold, etc. */
#define JS_HAS_STR_HTML_HELPERS 1 /* (no longer used) */
#define JS_HAS_OBJ_PROTO_PROP 1 /* has o.__proto__ etc. */
#define JS_HAS_OBJ_WATCHPOINT 1 /* has o.watch and o.unwatch */
#define JS_HAS_TOSOURCE 1 /* has Object/Array toSource method */
#define JS_HAS_CATCH_GUARD 1 /* has exception handling catch guard */
#define JS_HAS_UNEVAL 1 /* has uneval() top-level function */
#define JS_HAS_CONST 1 /* has JS2 const as alternative var */
#define JS_HAS_FUN_EXPR_STMT 1 /* has function expression statement */
#define JS_HAS_CONST 1 /* (no longer used) */
#define JS_HAS_FUN_EXPR_STMT 1 /* (no longer used) */
#define JS_HAS_NO_SUCH_METHOD 1 /* has o.__noSuchMethod__ handler */
#define JS_HAS_FOR_EACH_IN 1 /* has for each (lhs in iterable) */
#define JS_HAS_GENERATORS 1 /* has yield in generator function */
#define JS_HAS_BLOCK_SCOPE 1 /* has block scope via let/arraycomp */
#define JS_HAS_DESTRUCTURING 2 /* has [a,b] = ... or {p:a,q:b} = ... */
#define JS_HAS_GENERATORS 1 /* (no longer used) */
#define JS_HAS_BLOCK_SCOPE 1 /* (no longer used) */
#define JS_HAS_DESTRUCTURING 2 /* (no longer used) */
#define JS_HAS_GENERATOR_EXPRS 1 /* has (expr for (lhs in iterable)) */
#define JS_HAS_EXPR_CLOSURES 1 /* has function (formals) listexpr */
/* Support for JS_NewGlobalObject. */
/* (no longer used) */
#define JS_HAS_NEW_GLOBAL_OBJECT 1
/* Support for JS_MakeSystemObject. */
#define JS_HAS_MAKE_SYSTEM_OBJECT 1
/* Feature-test macro for evolving destructuring support. */
/* (no longer used) */
#define JS_HAS_DESTRUCTURING_SHORTHAND (JS_HAS_DESTRUCTURING == 2)
/*

View File

@ -3609,7 +3609,8 @@ END_CASE(JSOP_NEWINIT)
CASE(JSOP_NEWARRAY)
CASE(JSOP_SPREADCALLARRAY)
{
JSObject* obj = NewArrayOperation(cx, script, REGS.pc, GET_UINT24(REGS.pc));
uint32_t length = GET_UINT32(REGS.pc);
JSObject* obj = NewArrayOperation(cx, script, REGS.pc, length);
if (!obj)
goto error;
PUSH_OBJECT(*obj);
@ -3705,7 +3706,7 @@ CASE(JSOP_INITELEM_ARRAY)
ReservedRooted<JSObject*> obj(&rootObject0, &REGS.sp[-2].toObject());
uint32_t index = GET_UINT24(REGS.pc);
uint32_t index = GET_UINT32(REGS.pc);
if (!InitArrayElemOperation(cx, REGS.pc, obj, index, val))
goto error;

View File

@ -6,7 +6,8 @@
#include "vm/NativeObject-inl.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Casting.h"
#include "jswatchpoint.h"
@ -25,6 +26,7 @@
using namespace js;
using JS::GenericNaN;
using mozilla::ArrayLength;
using mozilla::DebugOnly;
using mozilla::PodCopy;
using mozilla::RoundUpPow2;
@ -397,7 +399,7 @@ NativeObject::growSlots(ExclusiveContext* cx, uint32_t oldCount, uint32_t newCou
* throttled well before the slot capacity can overflow.
*/
NativeObject::slotsSizeMustNotOverflow();
MOZ_ASSERT(newCount < NELEMENTS_LIMIT);
MOZ_ASSERT(newCount <= MAX_SLOTS_COUNT);
if (!oldCount) {
MOZ_ASSERT(!slots_);
@ -519,7 +521,7 @@ NativeObject::willBeSparseElements(uint32_t requiredCapacity, uint32_t newElemen
uint32_t cap = getDenseCapacity();
MOZ_ASSERT(requiredCapacity >= cap);
if (requiredCapacity >= NELEMENTS_LIMIT)
if (requiredCapacity > MAX_DENSE_ELEMENTS_COUNT)
return true;
uint32_t minimalDenseCount = requiredCapacity / SPARSE_DENSITY_RATIO;
@ -593,7 +595,7 @@ NativeObject::maybeDensifySparseElements(js::ExclusiveContext* cx, HandleNativeO
if (numDenseElements * SPARSE_DENSITY_RATIO < newInitializedLength)
return DenseElementResult::Incomplete;
if (newInitializedLength >= NELEMENTS_LIMIT)
if (newInitializedLength > MAX_DENSE_ELEMENTS_COUNT)
return DenseElementResult::Incomplete;
/*
@ -654,97 +656,95 @@ NativeObject::maybeDensifySparseElements(js::ExclusiveContext* cx, HandleNativeO
return DenseElementResult::Success;
}
// Round up |reqAllocated| to a good size. Up to 1 Mebi (i.e. 1,048,576) the
// slot count is usually a power-of-two:
// Given a requested allocation amount (in elements) and (potentially) the
// length of an array for which elements are being allocated, compute an actual
// allocation amount (in elements). (Allocation amounts include space for an
// ObjectElements instance, so a return value of |N| implies
// |N - ObjectElements::VALUES_PER_HEADER| usable elements.)
//
// 8, 16, 32, 64, ..., 256 Ki, 512 Ki, 1 Mi
// The requested/actual allocation distinction is meant to:
//
// Beyond that, we use this formula:
//
// count(n+1) = Math.ceil(count(n) * 1.125)
//
// where |count(n)| is the size of the nth bucket measured in MiSlots.
//
// These counts lets us add N elements to an array in amortized O(N) time.
// Having the second class means that for bigger arrays the constant factor is
// higher, but we waste less space.
//
// There is one exception to the above rule: for the power-of-two cases, if the
// chosen capacity would be 2/3 or more of the array's length, the chosen
// capacity is adjusted (up or down) to be equal to the array's length
// (assuming length is at least as large as the required capacity). This avoids
// the allocation of excess elements which are unlikely to be needed, either in
// this resizing or a subsequent one. The 2/3 factor is chosen so that
// exceptional resizings will at most triple the capacity, as opposed to the
// usual doubling.
// * preserve amortized O(N) time to add N elements;
// * minimize the number of unused elements beyond an array's length, and
// * provide at least SLOT_CAPACITY_MIN elements no matter what (so adding
// the first several elements to small arrays only needs one allocation).
//
// Note: the structure and behavior of this method follow along with
// UnboxedArrayObject::chooseCapacityIndex. Changes to the allocation strategy
// in one should generally be matched by the other.
/* static */ uint32_t
NativeObject::goodAllocated(uint32_t reqAllocated, uint32_t length = 0)
NativeObject::goodElementsAllocationAmount(uint32_t reqAllocated, uint32_t length = 0)
{
static const uint32_t Mebi = 1024 * 1024;
// Handle "small" requests primarily by doubling.
const uint32_t Mebi = 1 << 20;
if (reqAllocated < Mebi) {
uint32_t goodAmount = mozilla::AssertedCast<uint32_t>(RoundUpPow2(reqAllocated));
// This table was generated with this JavaScript code and a small amount
// subsequent reformatting:
//
// for (let n = 1, i = 0; i < 57; i++) {
// print((n * 1024 * 1024) + ', ');
// n = Math.ceil(n * 1.125);
// }
// print('0');
//
// The final element is a sentinel value.
static const uint32_t BigBuckets[] = {
1048576, 2097152, 3145728, 4194304, 5242880, 6291456, 7340032, 8388608,
9437184, 11534336, 13631488, 15728640, 17825792, 20971520, 24117248,
27262976, 31457280, 35651584, 40894464, 46137344, 52428800, 59768832,
68157440, 77594624, 88080384, 99614720, 112197632, 126877696,
143654912, 162529280, 183500800, 206569472, 232783872, 262144000,
295698432, 333447168, 375390208, 422576128, 476053504, 535822336,
602931200, 678428672, 763363328, 858783744, 966787072, 1088421888,
1224736768, 1377828864, 1550843904, 1744830464, 1962934272, 2208301056,
2485125120, 2796552192, 3146776576, 3541041152, 3984588800, 0
};
// This code relies very much on |goodAllocated| being a uint32_t.
uint32_t goodAllocated = reqAllocated;
if (goodAllocated < Mebi) {
goodAllocated = RoundUpPow2(goodAllocated);
// Look for the abovementioned exception.
uint32_t goodCapacity = goodAllocated - ObjectElements::VALUES_PER_HEADER;
// If |goodAmount| would be 2/3 or more of the array's length, adjust
// it (up or down) to be equal to the array's length. This avoids
// allocating excess elements that aren't likely to be needed, either
// in this resizing or a subsequent one. The 2/3 factor is chosen so
// that exceptional resizings will at most triple the capacity, as
// opposed to the usual doubling.
uint32_t goodCapacity = goodAmount - ObjectElements::VALUES_PER_HEADER;
uint32_t reqCapacity = reqAllocated - ObjectElements::VALUES_PER_HEADER;
if (length >= reqCapacity && goodCapacity > (length / 3) * 2)
goodAllocated = length + ObjectElements::VALUES_PER_HEADER;
goodAmount = length + ObjectElements::VALUES_PER_HEADER;
if (goodAllocated < SLOT_CAPACITY_MIN)
goodAllocated = SLOT_CAPACITY_MIN;
if (goodAmount < SLOT_CAPACITY_MIN)
goodAmount = SLOT_CAPACITY_MIN;
} else {
uint32_t i = 0;
while (true) {
uint32_t b = BigBuckets[i++];
if (b >= goodAllocated) {
// Found the first bucket greater than or equal to
// |goodAllocated|.
goodAllocated = b;
break;
} else if (b == 0) {
// Hit the end; return the maximum possible goodAllocated.
goodAllocated = 0xffffffff;
break;
}
}
return goodAmount;
}
return goodAllocated;
// The almost-doubling above wastes a lot of space for larger bucket sizes.
// For large amounts, switch to bucket sizes that obey this formula:
//
// count(n+1) = Math.ceil(count(n) * 1.125)
//
// where |count(n)| is the size of the nth bucket, measured in 2**20 slots.
// These bucket sizes still preserve amortized O(N) time to add N elements,
// just with a larger constant factor.
//
// The bucket size table below was generated with this JavaScript (and
// manual reformatting):
//
// for (let n = 1, i = 0; i < 34; i++) {
// print('0x' + (n * (1 << 20)).toString(16) + ', ');
// n = Math.ceil(n * 1.125);
// }
// print('MAX_DENSE_ELEMENTS_ALLOCATION');
//
// Dense array elements can't exceed |MAX_DENSE_ELEMENTS_ALLOCATION|, so
// |MAX_DENSE_ELEMENTS_ALLOCATION| is the biggest allowed length.
static const uint32_t BigBuckets[] = {
0x100000, 0x200000, 0x300000, 0x400000, 0x500000, 0x600000, 0x700000,
0x800000, 0x900000, 0xb00000, 0xd00000, 0xf00000, 0x1100000, 0x1400000,
0x1700000, 0x1a00000, 0x1e00000, 0x2200000, 0x2700000, 0x2c00000,
0x3200000, 0x3900000, 0x4100000, 0x4a00000, 0x5400000, 0x5f00000,
0x6b00000, 0x7900000, 0x8900000, 0x9b00000, 0xaf00000, 0xc500000,
0xde00000, 0xfa00000, MAX_DENSE_ELEMENTS_ALLOCATION
};
MOZ_ASSERT(BigBuckets[ArrayLength(BigBuckets) - 2] <= MAX_DENSE_ELEMENTS_ALLOCATION);
// Pick the first bucket that'll fit |reqAllocated|.
for (uint32_t b : BigBuckets) {
if (b >= reqAllocated)
return b;
}
// Otherwise, return the maximum bucket size.
return MAX_DENSE_ELEMENTS_ALLOCATION;
}
bool
NativeObject::growElements(ExclusiveContext* cx, uint32_t reqCapacity)
{
if (reqCapacity > MAX_DENSE_ELEMENTS_COUNT) {
ReportOutOfMemory(cx);
return false;
}
MOZ_ASSERT(nonProxyIsExtensible());
MOZ_ASSERT(canHaveNonEmptyElements());
if (denseElementsAreCopyOnWrite())
@ -753,17 +753,9 @@ NativeObject::growElements(ExclusiveContext* cx, uint32_t reqCapacity)
uint32_t oldCapacity = getDenseCapacity();
MOZ_ASSERT(oldCapacity < reqCapacity);
using mozilla::CheckedInt;
CheckedInt<uint32_t> checkedOldAllocated =
CheckedInt<uint32_t>(oldCapacity) + ObjectElements::VALUES_PER_HEADER;
CheckedInt<uint32_t> checkedReqAllocated =
CheckedInt<uint32_t>(reqCapacity) + ObjectElements::VALUES_PER_HEADER;
if (!checkedOldAllocated.isValid() || !checkedReqAllocated.isValid())
return false;
uint32_t reqAllocated = checkedReqAllocated.value();
uint32_t oldAllocated = checkedOldAllocated.value();
uint32_t reqAllocated = reqCapacity + ObjectElements::VALUES_PER_HEADER;
uint32_t oldAllocated = oldCapacity + ObjectElements::VALUES_PER_HEADER;
MOZ_ASSERT(oldAllocated <= MAX_DENSE_ELEMENTS_ALLOCATION);
uint32_t newAllocated;
if (is<ArrayObject>() && !as<ArrayObject>().lengthIsWritable()) {
@ -773,15 +765,15 @@ NativeObject::growElements(ExclusiveContext* cx, uint32_t reqCapacity)
// enforces this requirement.
newAllocated = reqAllocated;
} else {
newAllocated = goodAllocated(reqAllocated, getElementsHeader()->length);
newAllocated = goodElementsAllocationAmount(reqAllocated, getElementsHeader()->length);
}
uint32_t newCapacity = newAllocated - ObjectElements::VALUES_PER_HEADER;
MOZ_ASSERT(newCapacity > oldCapacity && newCapacity >= reqCapacity);
// Don't let nelements get close to wrapping around uint32_t.
if (newCapacity >= NELEMENTS_LIMIT)
return false;
// If newCapacity exceeds MAX_DENSE_ELEMENTS_COUNT, the array should become
// sparse.
MOZ_ASSERT(newCapacity <= MAX_DENSE_ELEMENTS_COUNT);
uint32_t initlen = getDenseInitializedLength();
@ -822,12 +814,13 @@ NativeObject::shrinkElements(ExclusiveContext* cx, uint32_t reqCapacity)
uint32_t oldAllocated = oldCapacity + ObjectElements::VALUES_PER_HEADER;
uint32_t reqAllocated = reqCapacity + ObjectElements::VALUES_PER_HEADER;
uint32_t newAllocated = goodAllocated(reqAllocated);
uint32_t newAllocated = goodElementsAllocationAmount(reqAllocated);
if (newAllocated == oldAllocated)
return; // Leave elements at its old size.
MOZ_ASSERT(newAllocated > ObjectElements::VALUES_PER_HEADER);
uint32_t newCapacity = newAllocated - ObjectElements::VALUES_PER_HEADER;
MOZ_ASSERT(newCapacity <= MAX_DENSE_ELEMENTS_COUNT);
HeapSlot* oldHeaderSlots = reinterpret_cast<HeapSlot*>(getElementsHeader());
HeapSlot* newHeaderSlots = ReallocateObjectBuffer<HeapSlot>(cx, this, oldHeaderSlots,
@ -852,12 +845,12 @@ NativeObject::CopyElementsForWrite(ExclusiveContext* cx, NativeObject* obj)
uint32_t initlen = obj->getDenseInitializedLength();
uint32_t allocated = initlen + ObjectElements::VALUES_PER_HEADER;
uint32_t newAllocated = goodAllocated(allocated);
uint32_t newAllocated = goodElementsAllocationAmount(allocated);
uint32_t newCapacity = newAllocated - ObjectElements::VALUES_PER_HEADER;
if (newCapacity >= NELEMENTS_LIMIT)
return false;
// COPY_ON_WRITE flags is set only if obj is a dense array.
MOZ_ASSERT(newCapacity <= MAX_DENSE_ELEMENTS_COUNT);
JSObject::writeBarrierPre(obj->getElementsHeader()->ownerObject());

View File

@ -556,8 +556,13 @@ class NativeObject : public JSObject
bool shadowingShapeChange(ExclusiveContext* cx, const Shape& shape);
bool clearFlag(ExclusiveContext* cx, BaseShape::Flag flag);
// The maximum number of slots in an object.
// |MAX_SLOTS_COUNT * sizeof(JS::Value)| shouldn't overflow
// int32_t (see slotsSizeMustNotOverflow).
static const uint32_t MAX_SLOTS_COUNT = (1 << 28) - 1;
static void slotsSizeMustNotOverflow() {
static_assert((NativeObject::NELEMENTS_LIMIT - 1) <= INT32_MAX / sizeof(JS::Value),
static_assert(NativeObject::MAX_SLOTS_COUNT <= INT32_MAX / sizeof(JS::Value),
"every caller of this method requires that a slot "
"number (or slot count) count multiplied by "
"sizeof(Value) can't overflow uint32_t (and sometimes "
@ -882,11 +887,19 @@ class NativeObject : public JSObject
/* Elements accessors. */
/* Upper bound on the number of elements in an object. */
static const uint32_t NELEMENTS_LIMIT = JS_BIT(28);
// The maximum size, in sizeof(Value), of the allocation used for an
// object's dense elements. (This includes space used to store an
// ObjectElements instance.)
// |MAX_DENSE_ELEMENTS_ALLOCATION * sizeof(JS::Value)| shouldn't overflow
// int32_t (see elementsSizeMustNotOverflow).
static const uint32_t MAX_DENSE_ELEMENTS_ALLOCATION = (1 << 28) - 1;
// The maximum number of usable dense elements in an object.
static const uint32_t MAX_DENSE_ELEMENTS_COUNT =
MAX_DENSE_ELEMENTS_ALLOCATION - ObjectElements::VALUES_PER_HEADER;
static void elementsSizeMustNotOverflow() {
static_assert((NativeObject::NELEMENTS_LIMIT - 1) <= INT32_MAX / sizeof(JS::Value),
static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT <= INT32_MAX / sizeof(JS::Value),
"every caller of this method require that an element "
"count multiplied by sizeof(Value) can't overflow "
"uint32_t (and sometimes int32_t ,too)");
@ -904,7 +917,7 @@ class NativeObject : public JSObject
return true;
}
static uint32_t goodAllocated(uint32_t n, uint32_t length);
static uint32_t goodElementsAllocationAmount(uint32_t n, uint32_t length);
bool growElements(ExclusiveContext* cx, uint32_t newcap);
void shrinkElements(ExclusiveContext* cx, uint32_t cap);
void setDynamicElements(ObjectElements* header) {

View File

@ -847,10 +847,10 @@
* This opcode takes the final length, which is preallocated.
* Category: Literals
* Type: Array
* Operands: uint24_t length
* Operands: uint32_t length
* Stack: => obj
*/ \
macro(JSOP_NEWARRAY, 90, "newarray", NULL, 4, 0, 1, JOF_UINT24) \
macro(JSOP_NEWARRAY, 90, "newarray", NULL, 5, 0, 1, JOF_UINT32) \
/*
* Pushes newly created object onto the stack.
*
@ -920,10 +920,10 @@
* property of 'obj' as 'val', pushes 'obj' onto the stack.
* Category: Literals
* Type: Array
* Operands: uint24_t index
* Operands: uint32_t index
* Stack: obj, val => obj
*/ \
macro(JSOP_INITELEM_ARRAY,96, "initelem_array", NULL, 4, 2, 1, JOF_UINT24|JOF_ELEM|JOF_SET|JOF_DETECTING) \
macro(JSOP_INITELEM_ARRAY,96, "initelem_array", NULL, 5, 2, 1, JOF_UINT32|JOF_ELEM|JOF_SET|JOF_DETECTING) \
\
/*
* Initialize a getter in an object literal.
@ -1277,13 +1277,12 @@
* the same semantics as JSOP_NEWARRAY, but is distinguished to avoid
* using unboxed arrays in spread calls, which would make compiling spread
* calls in baseline more complex.
*
* Category: Literals
* Type: Array
* Operands: uint24_t length
* Operands: uint32_t length
* Stack: => obj
*/ \
macro(JSOP_SPREADCALLARRAY, 126, "spreadcallarray", NULL, 4, 0, 1, JOF_UINT24) \
macro(JSOP_SPREADCALLARRAY, 126, "spreadcallarray", NULL, 5, 0, 1, JOF_UINT32) \
\
/*
* Defines the given function on the current scope.

View File

@ -29,7 +29,7 @@ namespace js {
*
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
*/
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 309;
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 310;
static const uint32_t XDR_BYTECODE_VERSION =
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);

View File

@ -5118,9 +5118,11 @@ ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
scale = gfxSize(1.0, 1.0);
}
// If this is a transform container layer, then pre-rendering might
// mean we try render a layer bigger than the max texture size. Apply
// clmaping to prevent this.
if (aTransform) {
// mean we try render a layer bigger than the max texture size. If we have
// tiling, that's not a problem, since we'll automatically choose a tiled
// layer for layers of that size. If not, we need to apply clamping to
// prevent this.
if (aTransform && !gfxPrefs::LayersTilesEnabled()) {
RestrictScaleToMaxLayerSize(scale, aVisibleRect, aContainerFrame, aLayer);
}
} else {

View File

@ -4606,8 +4606,7 @@ nsCSSRendering::GetTextDecorationRectInternal(const gfxPoint& aPt,
}
if (aVertical) {
r.y = baseline + floor(offset + 0.5); // this will need updating when we
// support sideways-left orientation
r.y = baseline + floor(offset + 0.5);
Swap(r.x, r.y);
Swap(r.width, r.height);
} else {

View File

@ -925,7 +925,8 @@ nsCaret::ComputeCaretRects(nsIFrame* aFrame, int32_t aFrameOffset,
{
NS_ASSERTION(aFrame, "Should have a frame here");
bool isVertical = aFrame->GetWritingMode().IsVertical();
WritingMode wm = aFrame->GetWritingMode();
bool isVertical = wm.IsVertical();
nscoord bidiIndicatorSize;
*aCaretRect = GetGeometryForFrame(aFrame, aFrameOffset, &bidiIndicatorSize);
@ -957,11 +958,20 @@ nsCaret::ComputeCaretRects(nsIFrame* aFrame, int32_t aFrameOffset,
}
bool isCaretRTL = caretBidiLevel % 2;
if (isVertical) {
aHookRect->SetRect(aCaretRect->XMost() - bidiIndicatorSize,
aCaretRect->y + (isCaretRTL ? bidiIndicatorSize * -1 :
aCaretRect->height),
aCaretRect->height,
bidiIndicatorSize);
bool isSidewaysLR = wm.IsVerticalLR() && !wm.IsLineInverted();
if (isSidewaysLR) {
aHookRect->SetRect(aCaretRect->x + bidiIndicatorSize,
aCaretRect->y + (!isCaretRTL ? bidiIndicatorSize * -1 :
aCaretRect->height),
aCaretRect->height,
bidiIndicatorSize);
} else {
aHookRect->SetRect(aCaretRect->XMost() - bidiIndicatorSize,
aCaretRect->y + (isCaretRTL ? bidiIndicatorSize * -1 :
aCaretRect->height),
aCaretRect->height,
bidiIndicatorSize);
}
} else {
aHookRect->SetRect(aCaretRect->x + (isCaretRTL ? bidiIndicatorSize * -1 :
aCaretRect->width),

View File

@ -2613,7 +2613,7 @@ NS_IMETHODIMP nsDocumentViewer::SelectAll()
rv = selection->RemoveAllRanges();
if (NS_FAILED(rv)) return rv;
mozilla::dom::Selection::AutoApplyUserSelectStyle userSelection(selection);
mozilla::dom::Selection::AutoUserInitiated userSelection(selection);
rv = selection->SelectAllChildren(bodyNode);
return rv;
}

View File

@ -6663,10 +6663,9 @@ nsLayoutUtils::GetTextRunOrientFlagsForStyle(nsStyleContext* aStyleContext)
return 0;
}
/* not yet implemented:
case NS_STYLE_WRITING_MODE_SIDEWAYS_LR:
return gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_LEFT;
*/
case NS_STYLE_WRITING_MODE_SIDEWAYS_RL:
return gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT;

View File

@ -103,7 +103,7 @@ public:
nsresult SubtractRange(RangeData* aRange, nsRange* aSubtract,
nsTArray<RangeData>* aOutput);
/**
* AddItem adds aRange to this Selection. If mApplyUserSelectStyle is true,
* AddItem adds aRange to this Selection. If mUserInitiated is true,
* then aRange is first scanned for -moz-user-select:none nodes and split up
* into multiple ranges to exclude those before adding the resulting ranges
* to this Selection.
@ -219,15 +219,15 @@ public:
nsresult NotifySelectionListeners();
friend struct AutoApplyUserSelectStyle;
struct MOZ_RAII AutoApplyUserSelectStyle
friend struct AutoUserInitiated;
struct MOZ_RAII AutoUserInitiated
{
explicit AutoApplyUserSelectStyle(Selection* aSelection
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mSavedValue(aSelection->mApplyUserSelectStyle)
explicit AutoUserInitiated(Selection* aSelection
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: mSavedValue(aSelection->mUserInitiated)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
aSelection->mApplyUserSelectStyle = true;
aSelection->mUserInitiated = true;
}
AutoRestore<bool> mSavedValue;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
@ -321,7 +321,7 @@ private:
* It determines whether we exclude -moz-user-select:none nodes or not,
* as well as whether selectstart events will be fired.
*/
bool mApplyUserSelectStyle;
bool mUserInitiated;
// Non-zero if we don't want any changes we make to the selection to be
// visible to content. If non-zero, content won't be notified about changes.

View File

@ -204,7 +204,15 @@ public:
BidiDir GetBidiDir() const { return BidiDir(mWritingMode & eBidiMask); }
/**
* Return true if LTR. (Convenience method)
* Return true if the inline flow direction is against physical direction
* (i.e. right-to-left or bottom-to-top).
* This occurs when writing-mode is sideways-lr OR direction is rtl (but not
* if both of those are true).
*/
bool IsInlineReversed() const { return !!(mWritingMode & eInlineFlowMask); }
/**
* Return true if bidi direction is LTR. (Convenience method)
*/
bool IsBidiLTR() const { return eBidiLTR == GetBidiDir(); }
@ -226,9 +234,7 @@ public:
/**
* True if line-over/line-under are inverted from block-start/block-end.
* This is true when
* - writing-mode is vertical-rl && text-orientation is sideways-left
* - writing-mode is vertical-lr && text-orientation is not sideways-left
* This is true only when writing-mode is vertical-lr.
*/
bool IsLineInverted() const { return !!(mWritingMode & eLineOrientMask); }
@ -315,23 +321,27 @@ public:
// bit 1 = the eInlineFlowMask value
// bit 2 = the eBlockFlowMask value
// bit 3 = the eLineOrientMask value
// Not all of these combinations can actually be specified via CSS: there
// is no horizontal-bt writing-mode, and no text-orientation value that
// produces "inverted" text. (The former 'sideways-left' value, no longer
// in the spec, would have produced this in vertical-rl mode.)
static const mozilla::css::Side kLogicalInlineSides[][2] = {
{ NS_SIDE_LEFT, NS_SIDE_RIGHT }, // horizontal-tb ltr
{ NS_SIDE_TOP, NS_SIDE_BOTTOM }, // vertical-rl ltr
{ NS_SIDE_RIGHT, NS_SIDE_LEFT }, // horizontal-tb rtl
{ NS_SIDE_BOTTOM, NS_SIDE_TOP }, // vertical-rl rtl
{ NS_SIDE_RIGHT, NS_SIDE_LEFT }, // (horizontal-bt) (inverted) ltr
{ NS_SIDE_TOP, NS_SIDE_BOTTOM }, // vertical-lr sideways-left rtl
{ NS_SIDE_LEFT, NS_SIDE_RIGHT }, // (horizontal-bt) (inverted) rtl
{ NS_SIDE_BOTTOM, NS_SIDE_TOP }, // vertical-lr sideways-left ltr
{ NS_SIDE_LEFT, NS_SIDE_RIGHT }, // horizontal-tb (inverted) rtl
{ NS_SIDE_TOP, NS_SIDE_BOTTOM }, // vertical-rl sideways-left rtl
{ NS_SIDE_RIGHT, NS_SIDE_LEFT }, // horizontal-tb (inverted) ltr
{ NS_SIDE_BOTTOM, NS_SIDE_TOP }, // vertical-rl sideways-left ltr
{ NS_SIDE_LEFT, NS_SIDE_RIGHT }, // (horizontal-bt) ltr
{ NS_SIDE_TOP, NS_SIDE_BOTTOM }, // vertical-lr ltr
{ NS_SIDE_RIGHT, NS_SIDE_LEFT }, // (horizontal-bt) rtl
{ NS_SIDE_BOTTOM, NS_SIDE_TOP }, // vertical-lr rtl
{ NS_SIDE_LEFT, NS_SIDE_RIGHT }, // horizontal-tb ltr
{ NS_SIDE_TOP, NS_SIDE_BOTTOM }, // vertical-rl ltr
{ NS_SIDE_RIGHT, NS_SIDE_LEFT }, // horizontal-tb rtl
{ NS_SIDE_BOTTOM, NS_SIDE_TOP }, // vertical-rl rtl
{ NS_SIDE_RIGHT, NS_SIDE_LEFT }, // (horizontal-bt) (inverted) ltr
{ NS_SIDE_TOP, NS_SIDE_BOTTOM }, // sideways-lr rtl
{ NS_SIDE_LEFT, NS_SIDE_RIGHT }, // (horizontal-bt) (inverted) rtl
{ NS_SIDE_BOTTOM, NS_SIDE_TOP }, // sideways-lr ltr
{ NS_SIDE_LEFT, NS_SIDE_RIGHT }, // horizontal-tb (inverted) rtl
{ NS_SIDE_TOP, NS_SIDE_BOTTOM }, // vertical-rl (inverted) rtl
{ NS_SIDE_RIGHT, NS_SIDE_LEFT }, // horizontal-tb (inverted) ltr
{ NS_SIDE_BOTTOM, NS_SIDE_TOP }, // vertical-rl (inverted) ltr
{ NS_SIDE_LEFT, NS_SIDE_RIGHT }, // (horizontal-bt) ltr
{ NS_SIDE_TOP, NS_SIDE_BOTTOM }, // vertical-lr ltr
{ NS_SIDE_RIGHT, NS_SIDE_LEFT }, // (horizontal-bt) rtl
{ NS_SIDE_BOTTOM, NS_SIDE_TOP }, // vertical-lr rtl
};
// Inline axis sides depend on all three of writing-mode, text-orientation
@ -426,7 +436,7 @@ public:
{
auto side = static_cast<LogicalSide>(aDir);
if (IsInline(side)) {
return IsBidiLTR() ? side : GetOppositeSide(side);
return !IsInlineReversed() ? side : GetOppositeSide(side);
}
return !IsLineInverted() ? side : GetOppositeSide(side);
}
@ -686,13 +696,13 @@ public:
#endif
{
if (aWritingMode.IsVertical()) {
I() = aWritingMode.IsBidiLTR() ? aPoint.y
: aContainerSize.height - aPoint.y;
I() = aWritingMode.IsInlineReversed() ? aContainerSize.height - aPoint.y
: aPoint.y;
B() = aWritingMode.IsVerticalLR() ? aPoint.x
: aContainerSize.width - aPoint.x;
} else {
I() = aWritingMode.IsBidiLTR() ? aPoint.x
: aContainerSize.width - aPoint.x;
I() = aWritingMode.IsInlineReversed() ? aContainerSize.width - aPoint.x
: aPoint.x;
B() = aPoint.y;
}
}
@ -737,11 +747,11 @@ public:
if (aWritingMode.IsVertical()) {
return nsPoint(aWritingMode.IsVerticalLR()
? B() : aContainerSize.width - B(),
aWritingMode.IsBidiLTR()
? I() : aContainerSize.height - I());
aWritingMode.IsInlineReversed()
? aContainerSize.height - I() : I());
} else {
return nsPoint(aWritingMode.IsBidiLTR()
? I() : aContainerSize.width - I(),
return nsPoint(aWritingMode.IsInlineReversed()
? aContainerSize.width - I() : I(),
B());
}
}
@ -1097,22 +1107,22 @@ public:
mMargin.top = aPhysicalMargin.right;
mMargin.bottom = aPhysicalMargin.left;
}
if (aWritingMode.IsBidiLTR()) {
mMargin.left = aPhysicalMargin.top;
mMargin.right = aPhysicalMargin.bottom;
} else {
if (aWritingMode.IsInlineReversed()) {
mMargin.left = aPhysicalMargin.bottom;
mMargin.right = aPhysicalMargin.top;
} else {
mMargin.left = aPhysicalMargin.top;
mMargin.right = aPhysicalMargin.bottom;
}
} else {
mMargin.top = aPhysicalMargin.top;
mMargin.bottom = aPhysicalMargin.bottom;
if (aWritingMode.IsBidiLTR()) {
mMargin.left = aPhysicalMargin.left;
mMargin.right = aPhysicalMargin.right;
} else {
if (aWritingMode.IsInlineReversed()) {
mMargin.left = aPhysicalMargin.right;
mMargin.right = aPhysicalMargin.left;
} else {
mMargin.left = aPhysicalMargin.left;
mMargin.right = aPhysicalMargin.right;
}
}
}
@ -1211,14 +1221,14 @@ public:
{
CHECK_WRITING_MODE(aWritingMode);
return aWritingMode.IsVertical() ?
(aWritingMode.IsBidiLTR() ? IStart() : IEnd()) : BStart();
(aWritingMode.IsInlineReversed() ? IEnd() : IStart()) : BStart();
}
nscoord Bottom(WritingMode aWritingMode) const
{
CHECK_WRITING_MODE(aWritingMode);
return aWritingMode.IsVertical() ?
(aWritingMode.IsBidiLTR() ? IEnd() : IStart()) : BEnd();
(aWritingMode.IsInlineReversed() ? IStart() : IEnd()) : BEnd();
}
nscoord Left(WritingMode aWritingMode) const
@ -1226,7 +1236,7 @@ public:
CHECK_WRITING_MODE(aWritingMode);
return aWritingMode.IsVertical() ?
(aWritingMode.IsVerticalLR() ? BStart() : BEnd()) :
(aWritingMode.IsBidiLTR() ? IStart() : IEnd());
(aWritingMode.IsInlineReversed() ? IEnd() : IStart());
}
nscoord Right(WritingMode aWritingMode) const
@ -1234,7 +1244,7 @@ public:
CHECK_WRITING_MODE(aWritingMode);
return aWritingMode.IsVertical() ?
(aWritingMode.IsVerticalLR() ? BEnd() : BStart()) :
(aWritingMode.IsBidiLTR() ? IEnd() : IStart());
(aWritingMode.IsInlineReversed() ? IStart() : IEnd());
}
nscoord LeftRight(WritingMode aWritingMode) const
@ -1264,15 +1274,15 @@ public:
CHECK_WRITING_MODE(aWritingMode);
return aWritingMode.IsVertical()
? (aWritingMode.IsVerticalLR()
? (aWritingMode.IsBidiLTR()
? nsMargin(IStart(), BEnd(), IEnd(), BStart())
: nsMargin(IEnd(), BEnd(), IStart(), BStart()))
: (aWritingMode.IsBidiLTR()
? nsMargin(IStart(), BStart(), IEnd(), BEnd())
: nsMargin(IEnd(), BStart(), IStart(), BEnd())))
: (aWritingMode.IsBidiLTR()
? nsMargin(BStart(), IEnd(), BEnd(), IStart())
: nsMargin(BStart(), IStart(), BEnd(), IEnd()));
? (aWritingMode.IsInlineReversed()
? nsMargin(IEnd(), BEnd(), IStart(), BStart())
: nsMargin(IStart(), BEnd(), IEnd(), BStart()))
: (aWritingMode.IsInlineReversed()
? nsMargin(IEnd(), BStart(), IStart(), BEnd())
: nsMargin(IStart(), BStart(), IEnd(), BEnd())))
: (aWritingMode.IsInlineReversed()
? nsMargin(BStart(), IStart(), BEnd(), IEnd())
: nsMargin(BStart(), IEnd(), BEnd(), IStart()));
}
/**
@ -1439,13 +1449,13 @@ public:
if (aWritingMode.IsVertical()) {
mRect.y = aWritingMode.IsVerticalLR()
? aRect.x : aContainerSize.width - aRect.XMost();
mRect.x = aWritingMode.IsBidiLTR()
? aRect.y : aContainerSize.height - aRect.YMost();
mRect.x = aWritingMode.IsInlineReversed()
? aContainerSize.height - aRect.YMost() : aRect.y;
mRect.height = aRect.width;
mRect.width = aRect.height;
} else {
mRect.x = aWritingMode.IsBidiLTR()
? aRect.x : aContainerSize.width - aRect.XMost();
mRect.x = aWritingMode.IsInlineReversed()
? aContainerSize.width - aRect.XMost() : aRect.x;
mRect.y = aRect.y;
mRect.width = aRect.width;
mRect.height = aRect.height;
@ -1548,8 +1558,8 @@ public:
return aWritingMode.IsVerticalLR() ?
mRect.Y() : aContainerWidth - mRect.YMost();
} else {
return aWritingMode.IsBidiLTR() ?
mRect.X() : aContainerWidth - mRect.XMost();
return aWritingMode.IsInlineReversed() ?
aContainerWidth - mRect.XMost() : mRect.X();
}
}
@ -1557,8 +1567,8 @@ public:
{
CHECK_WRITING_MODE(aWritingMode);
if (aWritingMode.IsVertical()) {
return aWritingMode.IsBidiLTR() ? mRect.X()
: aContainerHeight - mRect.XMost();
return aWritingMode.IsInlineReversed() ? aContainerHeight - mRect.XMost()
: mRect.X();
} else {
return mRect.Y();
}
@ -1583,8 +1593,8 @@ public:
return aWritingMode.IsVerticalLR() ?
mRect.YMost() : aContainerWidth - mRect.Y();
} else {
return aWritingMode.IsBidiLTR() ?
mRect.XMost() : aContainerWidth - mRect.X();
return aWritingMode.IsInlineReversed() ?
aContainerWidth - mRect.X() : mRect.XMost();
}
}
@ -1592,8 +1602,8 @@ public:
{
CHECK_WRITING_MODE(aWritingMode);
if (aWritingMode.IsVertical()) {
return aWritingMode.IsBidiLTR() ? mRect.XMost()
: aContainerHeight - mRect.x;
return aWritingMode.IsInlineReversed() ? aContainerHeight - mRect.x
: mRect.XMost();
} else {
return mRect.YMost();
}
@ -1707,12 +1717,12 @@ public:
if (aWritingMode.IsVertical()) {
return nsRect(aWritingMode.IsVerticalLR()
? BStart() : aContainerSize.width - BEnd(),
aWritingMode.IsBidiLTR()
? IStart() : aContainerSize.height - IEnd(),
aWritingMode.IsInlineReversed()
? aContainerSize.height - IEnd() : IStart(),
BSize(), ISize());
} else {
return nsRect(aWritingMode.IsBidiLTR()
? IStart() : aContainerSize.width - IEnd(),
return nsRect(aWritingMode.IsInlineReversed()
? aContainerSize.width - IEnd() : IStart(),
BStart(), ISize(), BSize());
}
}

View File

@ -1187,7 +1187,7 @@ nsImageFrame::DisplayAltText(nsPresContext* aPresContext,
nscoord x, y;
if (isVertical) {
x = pt.x + maxDescent; // XXX will need update for sideways-left
x = pt.x + maxDescent;
if (wm.IsBidiLTR()) {
y = aRect.y;
dir = NSBIDI_LTR;

View File

@ -350,7 +350,7 @@ struct MOZ_RAII AutoPrepareFocusRange
if (aSelection->mFrameSelection->IsUserSelectionReason()) {
mUserSelect.emplace(aSelection);
}
bool userSelection = aSelection->mApplyUserSelectStyle;
bool userSelection = aSelection->mUserInitiated;
nsTArray<RangeData>& ranges = aSelection->mRanges;
if (!userSelection ||
@ -424,7 +424,7 @@ struct MOZ_RAII AutoPrepareFocusRange
}
}
Maybe<Selection::AutoApplyUserSelectStyle> mUserSelect;
Maybe<Selection::AutoUserInitiated> mUserSelect;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
@ -1682,7 +1682,7 @@ nsFrameSelection::TakeFocus(nsIContent* aNewFocus,
if (!mDomSelections[index])
return NS_ERROR_NULL_POINTER;
Maybe<Selection::AutoApplyUserSelectStyle> userSelect;
Maybe<Selection::AutoUserInitiated> userSelect;
if (IsUserSelectionReason()) {
userSelect.emplace(mDomSelections[index]);
}
@ -3331,7 +3331,7 @@ Selection::Selection()
: mCachedOffsetForFrame(nullptr)
, mDirection(eDirNext)
, mType(nsISelectionController::SELECTION_NORMAL)
, mApplyUserSelectStyle(false)
, mUserInitiated(false)
, mSelectionChangeBlockerCount(0)
{
}
@ -3341,7 +3341,7 @@ Selection::Selection(nsFrameSelection* aList)
, mCachedOffsetForFrame(nullptr)
, mDirection(eDirNext)
, mType(nsISelectionController::SELECTION_NORMAL)
, mApplyUserSelectStyle(false)
, mUserInitiated(false)
, mSelectionChangeBlockerCount(0)
{
}
@ -3700,10 +3700,7 @@ Selection::AddItem(nsRange* aItem, int32_t* aOutIndex, bool aNoStartSelect)
NS_ASSERTION(aOutIndex, "aOutIndex can't be null");
// XXX Rename mApplyUserSelectStyle? Not the best name (as it is also being
// used to detect here whether the event is user initiated for the purposes of
// dispatching the selectstart event).
if (mApplyUserSelectStyle) {
if (mUserInitiated) {
nsAutoTArray<nsRefPtr<nsRange>, 4> rangesToAdd;
*aOutIndex = -1;

View File

@ -5311,6 +5311,7 @@ nsTextFrame::DrawSelectionDecorations(gfxContext* aContext,
const gfxFont::Metrics& aFontMetrics,
DrawPathCallbacks* aCallbacks,
bool aVertical,
gfxFloat aDecorationOffsetDir,
uint8_t aDecoration)
{
gfxPoint pt(aPt);
@ -5417,8 +5418,8 @@ nsTextFrame::DrawSelectionDecorations(gfxContext* aContext,
size.height *= relativeSize;
PaintDecorationLine(aContext, aDirtyRect, color, nullptr, pt,
(aVertical ? (pt.y - aPt.y) : (pt.x - aPt.x)) + aICoordInFrame,
size, aAscent, offset, aDecoration, style, eSelectionDecoration,
aCallbacks, aVertical, descentLimit);
size, aAscent, offset * aDecorationOffsetDir, aDecoration, style,
eSelectionDecoration, aCallbacks, aVertical, descentLimit);
}
/* static */
@ -5792,7 +5793,7 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
mTextRun->GetAdvanceWidth(offset, length, &aProvider);
if (NS_GET_A(background) > 0) {
gfxRect bgRect;
gfxFloat offs = iOffset - (mTextRun->IsRightToLeft() ? advance : 0);
gfxFloat offs = iOffset - (mTextRun->IsInlineReversed() ? advance : 0);
if (vertical) {
bgRect = gfxRect(aFramePt.x, aFramePt.y + offs,
GetSize().width, advance);
@ -5829,7 +5830,7 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
GetSelectionTextShadow(this, type, aTextPaintStyle, &shadow);
if (shadow) {
nscoord startEdge = iOffset;
if (mTextRun->IsRightToLeft()) {
if (mTextRun->IsInlineReversed()) {
startEdge -= mTextRun->GetAdvanceWidth(offset, length, &aProvider) +
hyphenWidth;
}
@ -5919,6 +5920,7 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
}
gfxRect dirtyRect(aDirtyRect.x / app, aDirtyRect.y / app,
aDirtyRect.width / app, aDirtyRect.height / app);
gfxFloat decorationOffsetDir = mTextRun->IsSidewaysLeft() ? -1.0 : 1.0;
SelectionType type;
TextRangeStyle selectedStyle;
while (iterator.GetNextSegment(&iOffset, &offset, &length, &hyphenWidth,
@ -5928,17 +5930,18 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
if (type == aSelectionType) {
if (verticalRun) {
pt.y = (aFramePt.y + iOffset -
(mTextRun->IsRightToLeft() ? advance : 0)) / app;
(mTextRun->IsInlineReversed() ? advance : 0)) / app;
} else {
pt.x = (aFramePt.x + iOffset -
(mTextRun->IsRightToLeft() ? advance : 0)) / app;
(mTextRun->IsInlineReversed() ? advance : 0)) / app;
}
gfxFloat width = Abs(advance) / app;
gfxFloat xInFrame = pt.x - (aFramePt.x / app);
DrawSelectionDecorations(aCtx, dirtyRect, aSelectionType,
aTextPaintStyle, selectedStyle, pt, xInFrame,
width, mAscent / app, decorationMetrics,
aCallbacks, verticalRun, kDecoration);
aCallbacks, verticalRun, decorationOffsetDir,
kDecoration);
}
iterator.UpdateWithAdvance(advance);
}
@ -6246,7 +6249,7 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
provider.InitializeForDisplay(!IsSelected());
gfxContext* ctx = aRenderingContext->ThebesContext();
const bool rtl = mTextRun->IsRightToLeft();
const bool reversed = mTextRun->IsInlineReversed();
const bool verticalRun = mTextRun->IsVertical();
WritingMode wm = GetWritingMode();
const nscoord frameWidth = GetSize().width;
@ -6261,10 +6264,11 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
nsLayoutUtils::GetSnappedBaselineX(this, ctx, aPt.x + frameWidth,
-mAscent);
}
textBaselinePt.y = rtl ? aPt.y + GetSize().height : aPt.y;
textBaselinePt.y = reversed ? aPt.y + GetSize().height : aPt.y;
} else {
textBaselinePt = gfxPoint(rtl ? gfxFloat(aPt.x + frameWidth) : framePt.x,
nsLayoutUtils::GetSnappedBaselineY(this, ctx, aPt.y, mAscent));
textBaselinePt =
gfxPoint(reversed ? gfxFloat(aPt.x + frameWidth) : framePt.x,
nsLayoutUtils::GetSnappedBaselineY(this, ctx, aPt.y, mAscent));
}
uint32_t startOffset = provider.GetStart().GetSkippedOffset();
uint32_t maxLength = ComputeTransformedLength(provider);
@ -6274,9 +6278,9 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
return;
}
if (verticalRun) {
textBaselinePt.y += rtl ? -snappedEndEdge : snappedStartEdge;
textBaselinePt.y += reversed ? -snappedEndEdge : snappedStartEdge;
} else {
textBaselinePt.x += rtl ? -snappedEndEdge : snappedStartEdge;
textBaselinePt.x += reversed ? -snappedEndEdge : snappedStartEdge;
}
nsCharClipDisplayItem::ClipEdges clipEdges(aItem, snappedStartEdge,
snappedEndEdge);
@ -6432,6 +6436,10 @@ nsTextFrame::DrawTextRunAndDecorations(
nscoord inflationMinFontSize =
nsLayoutUtils::InflationMinFontSizeFor(this);
// The decoration-line offsets need to be reversed for sideways-lr mode,
// so we will multiply the values from metrics by this factor.
gfxFloat decorationOffsetDir = mTextRun->IsSidewaysLeft() ? -1.0 : 1.0;
// Underlines
for (uint32_t i = aDecorations.mUnderlines.Length(); i-- > 0; ) {
const LineDecoration& dec = aDecorations.mUnderlines[i];
@ -6450,7 +6458,8 @@ nsTextFrame::DrawTextRunAndDecorations(
PaintDecorationLine(aCtx, dirtyRect, dec.mColor,
aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
metrics.underlineOffset, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
decorationOffsetDir * metrics.underlineOffset,
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
dec.mStyle, eNormalDecoration, aCallbacks, verticalRun);
}
// Overlines
@ -6471,7 +6480,8 @@ nsTextFrame::DrawTextRunAndDecorations(
PaintDecorationLine(aCtx, dirtyRect, dec.mColor,
aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
metrics.maxAscent, NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, dec.mStyle,
decorationOffsetDir * metrics.maxAscent,
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, dec.mStyle,
eNormalDecoration, aCallbacks, verticalRun);
}
@ -6498,7 +6508,8 @@ nsTextFrame::DrawTextRunAndDecorations(
PaintDecorationLine(aCtx, dirtyRect, dec.mColor,
aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
metrics.strikeoutOffset, NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH,
decorationOffsetDir * metrics.strikeoutOffset,
NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH,
dec.mStyle, eNormalDecoration, aCallbacks, verticalRun);
}
}
@ -6631,9 +6642,9 @@ nsTextFrame::GetCharacterOffsetAtFramePointInternal(nsPoint aPoint,
PropertyProvider provider(this, iter, nsTextFrame::eInflated);
// Trim leading but not trailing whitespace if possible
provider.InitializeForDisplay(false);
gfxFloat width = mTextRun->IsVertical() ?
(mTextRun->IsRightToLeft() ? mRect.height - aPoint.y : aPoint.y) :
(mTextRun->IsRightToLeft() ? mRect.width - aPoint.x : aPoint.x);
gfxFloat width = mTextRun->IsVertical()
? (mTextRun->IsInlineReversed() ? mRect.height - aPoint.y : aPoint.y)
: (mTextRun->IsInlineReversed() ? mRect.width - aPoint.x : aPoint.x);
gfxFloat fitWidth;
uint32_t skippedLength = ComputeTransformedLength(provider);
@ -6860,13 +6871,13 @@ nsTextFrame::GetPointFromOffset(int32_t inOffset,
nscoord iSize = NSToCoordCeilClamped(advance);
if (mTextRun->IsVertical()) {
if (mTextRun->IsRightToLeft()) {
if (mTextRun->IsInlineReversed()) {
outPoint->y = mRect.height - iSize;
} else {
outPoint->y = iSize;
}
} else {
if (mTextRun->IsRightToLeft()) {
if (mTextRun->IsInlineReversed()) {
outPoint->x = mRect.width - iSize;
} else {
outPoint->x = iSize;

View File

@ -746,6 +746,7 @@ protected:
const gfxFont::Metrics& aFontMetrics,
DrawPathCallbacks* aCallbacks,
bool aVertical,
gfxFloat aDecorationOffsetDir,
uint8_t aDecoration);
enum DecorationType
{

View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<style>
.slr {
writing-mode: sideways-lr;
}
</style>
</head>
<body>
<div style="height:0px;width:0px;overflow:visible">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);display:inline-block;margin-top:calc(100vh - 316px);"></div>
</div>
<div style="height:0px;width:0px;overflow:visible">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);display:inline-block;margin-top:calc(100vh - 216px);"></div>
</div>
<div class="slr" style="background:silver; height: calc(100vh - 16px);">
<div style="height:100px;">This text should appear BELOW the red and green blocks.</div>
</div>
</body>
</html>

View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html class="slr">
<head>
<style>
.slr {
writing-mode: sideways-lr;
}
</style>
</head>
<body>
<div style="height:300px" dir="rtl">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);float:right;"></div>
</div>
<div style="height:200px">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);float:right;"></div>
</div>
<div style="background:silver">
This text should appear BELOW the red and green blocks.
</div>
</body>
</html>

View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html class="slr">
<head>
<style>
.slr {
writing-mode: sideways-lr;
}
</style>
</head>
<body>
<div style="height:300px">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);float:right;"></div>
</div>
<div style="height:200px" dir="rtl">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);float:right;"></div>
</div>
<div style="background:silver">
This text should appear BELOW the red and green blocks.
</div>
</body>
</html>

View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html class="slr">
<head>
<style>
.slr {
writing-mode: sideways-lr;
}
</style>
</head>
<body>
<div style="height:300px" dir="rtl">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);float:right;"></div>
</div>
<div style="height:200px" dir="rtl">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);float:right;"></div>
</div>
<div style="background:silver">
This text should appear BELOW the red and green blocks.
</div>
</body>
</html>

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html class="slr">
<head>
<style>
.slr {
writing-mode: sideways-lr;
}
</style>
</head>
<body>
<div dir="rtl" style="height:300px">
<div style="height:300px">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);float:right;"></div>
</div>
<div style="height:200px">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);float:right;"></div>
</div>
</div>
<div style="background:silver">
This text should appear BELOW the red and green blocks.
</div>
</body>
</html>

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<style>
.slr {
writing-mode: sideways-lr;
}
</style>
</head>
<body>
<div style="height:0px;width:0px;overflow:visible">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);display:inline-block;margin-top:calc(100vh - 116px);"></div>
</div>
<div style="height:0px;width:0px;overflow:visible">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);display:inline-block;margin-top:calc(100vh - 216px);"></div>
</div>
<div style="height:0px;width:0px;overflow:visible">
<div class="slr" style="background:silver; height: calc(100vh - 16px);">
<div style="margin-bottom:200px;">This text should appear ABOVE the green and red blocks.</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html class="slr">
<head>
<style>
.slr {
writing-mode: sideways-lr;
}
</style>
</head>
<body>
<div dir="rtl" style="height:300px">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);float:left;"></div>
</div>
<div style="height:200px">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);float:left;"></div>
</div>
<div style="background:silver">
This text should appear ABOVE the green and red blocks.
</div>
</body>
</html>

View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html class="slr">
<head>
<style>
.slr {
writing-mode: sideways-lr;
}
</style>
</head>
<body>
<div style="height:300px">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);float:left;"></div>
</div>
<div dir="rtl" style="height:200px">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);float:left;"></div>
</div>
<div style="background:silver">
This text should appear ABOVE the green and red blocks.
</div>
</body>
</html>

View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html class="slr">
<head>
<style>
.slr {
writing-mode: sideways-lr;
}
</style>
</head>
<body>
<div dir="rtl" style="height:300px">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);float:left;"></div>
</div>
<div dir="rtl" style="height:200px">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);float:left;"></div>
</div>
<div style="background:silver">
This text should appear ABOVE the green and red blocks.
</div>
</body>
</html>

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html class="slr">
<head>
<style>
.slr {
writing-mode: sideways-lr;
}
</style>
</head>
<body>
<div dir="rtl" style="inline-size:-moz-fit-content">
<div style="height:300px">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);float:left;"></div>
</div>
<div style="height:200px">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);float:left;"></div>
</div>
</div>
<div style="background:silver">
This text should appear ABOVE the green and red blocks.
</div>
</body>
</html>

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<style>
.slr {
writing-mode: sideways-lr;
}
</style>
</head>
<body>
<div>
<div style="height:0px;width:0px;overflow:visible">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);display:inline-block;margin-top:200px;"></div>
</div>
<div style="height:0px;width:0px;overflow:visible">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);display:inline-block;margin-top:100px;"></div>
</div>
<div class="slr" style="background:silver; height:calc(100vh - 16px);">
<div style="margin-bottom:calc(100vh - 116px); direction:rtl">This text should appear ABOVE the green and red blocks.</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html class="slr">
<head>
<style>
.slr {
writing-mode: sideways-lr;
}
</style>
</head>
<body>
<div style="direction: rtl;">
<div dir="ltr" style="height:300px">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);float:left;"></div>
</div>
<div style="height:200px">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);float:left;"></div>
</div>
<div style="background:silver">
This text should appear ABOVE the green and red blocks.
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html class="slr">
<head>
<style>
.slr {
writing-mode: sideways-lr;
}
</style>
</head>
<body>
<div style="direction: rtl;">
<div style="height:300px">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);float:left;"></div>
</div>
<div dir="ltr" style="height:200px">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);float:left;"></div>
</div>
<div style="background:silver">
This text should appear ABOVE the green and red blocks.
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html class="slr">
<head>
<style>
.slr {
writing-mode: sideways-lr;
}
</style>
</head>
<body>
<div style="direction: rtl;">
<div dir="ltr" style="height:300px">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);float:left;"></div>
</div>
<div dir="ltr" style="height:200px">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);float:left"></div>
</div>
<div style="background:silver">
This text should appear ABOVE the green and red blocks.
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html class="slr">
<head>
<style>
.slr {
writing-mode: sideways-lr;
}
</style>
</head>
<body>
<div style="direction: rtl;">
<div dir="ltr" style="inline-size:-moz-fit-content">
<div style="height:300px">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);float:left;"></div>
</div>
<div style="height:200px">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);float:left;"></div>
</div>
</div>
<div style="background:silver">
This text should appear ABOVE the green and red blocks.
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<style>
.slr {
writing-mode: sideways-lr;
direction: rtl;
}
</style>
</head>
<body>
<div>
<div style="height:0px;width:0px;overflow:visible">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);display:inline-block;margin-top:0"></div>
</div>
<div style="height:0px;width:0px;overflow:visible">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);display:inline-block;margin-top:100px"></div>
</div>
<div class="slr" style="background:silver; height: calc(100vh - 16px);">
<div style="height: calc(100vh - 216px); margin-top: 200px">This text should appear BELOW the red and green blocks.</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html class="slr">
<head>
<style>
.slr {
writing-mode: sideways-lr;
direction: rtl;
}
</style>
</head>
<body>
<div>
<div dir="ltr" style="height:300px">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);float:right;"></div>
</div>
<div style="height:200px">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);float:right;"></div>
</div>
<div style="background:silver">
This text should appear BELOW the red and green blocks.
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html class="slr">
<head>
<style>
.slr {
writing-mode: sideways-lr;
direction: rtl;
}
</style>
</head>
<body>
<div>
<div style="height:300px">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);float:right;"></div>
</div>
<div dir="ltr" style="height:200px">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);float:right;"></div>
</div>
<div style="background:silver">
This text should appear BELOW the red and green blocks.
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html class="slr">
<head>
<style>
.slr {
writing-mode: sideways-lr;
direction: rtl;
}
</style>
</head>
<body>
<div>
<div dir="ltr" style="height:300px">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);float:right;"></div>
</div>
<div dir="ltr" style="height:200px">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);float:right;"></div>
</div>
<div style="background:silver">
This text should appear BELOW the red and green blocks.
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html class="slr">
<head>
<style>
.slr {
writing-mode: sideways-lr;
direction: rtl;
}
</style>
</head>
<body>
<div>
<div dir="ltr" style="inline-size:-moz-fit-content">
<div style="height:300px">
<div style="height:100px;width:120px;background:rgba(0,255,0,0.8);float:right;"></div>
</div>
<div style="height:200px">
<div style="height:100px;width:150px;background:rgba(255,0,0,0.8);float:right;"></div>
</div>
</div>
<div style="background:silver">
This text should appear BELOW the red and green blocks.
</div>
</div>
</body>
</html>

View File

@ -88,3 +88,20 @@ fuzzy-if(OSX==1010,26,7) fuzzy-if(Android,16,2) == orthogonal-floats-1a.html ort
fuzzy-if(OSX==1010,26,7) == orthogonal-floats-1b.html orthogonal-floats-1-ref.html
fuzzy-if(OSX==1010,103,802) fuzzy-if(winWidget,116,700) HTTP(..) == orthogonal-floats-1c.html orthogonal-floats-1-ref.html
fuzzy-if(OSX==1010,103,802) fuzzy-if(winWidget,116,700) HTTP(..) == orthogonal-floats-1d.html orthogonal-floats-1-ref.html
== float-in-rtl-slr-1a.html float-in-rtl-slr-1-ref.html
== float-in-rtl-slr-1b.html float-in-rtl-slr-1-ref.html
== float-in-rtl-slr-1c.html float-in-rtl-slr-1-ref.html
== float-in-rtl-slr-1d.html float-in-rtl-slr-1-ref.html
== float-in-rtl-slr-2a.html float-in-rtl-slr-2-ref.html
== float-in-rtl-slr-2b.html float-in-rtl-slr-2-ref.html
== float-in-rtl-slr-2c.html float-in-rtl-slr-2-ref.html
== float-in-rtl-slr-2d.html float-in-rtl-slr-2-ref.html
== float-in-rtl-slr-3a.html float-in-rtl-slr-3-ref.html
== float-in-rtl-slr-3b.html float-in-rtl-slr-3-ref.html
== float-in-rtl-slr-3c.html float-in-rtl-slr-3-ref.html
== float-in-rtl-slr-3d.html float-in-rtl-slr-3-ref.html
== float-in-rtl-slr-4a.html float-in-rtl-slr-4-ref.html
== float-in-rtl-slr-4b.html float-in-rtl-slr-4-ref.html
== float-in-rtl-slr-4c.html float-in-rtl-slr-4-ref.html
== float-in-rtl-slr-4d.html float-in-rtl-slr-4-ref.html

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<style>
div { padding: 5px; display: inline-block; }
span { display: block; width: 2em; }
span:nth-child(1) { background: red; height: 1em; }
span:nth-child(2) { background: orange; height: 1.1em; }
span:nth-child(3) { background: yellow; height: 1.3em; }
span:nth-child(4) { background: green; height: 1.5em; }
span:nth-child(5) { background: blue; height: 1.7em; }
span:nth-child(6) { background: indigo; height: 1.9em; }
span:nth-child(7) { background: violet; height: 2em; }
</style>
</head>
<body>
<p>All four columns should look the same:
<div><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
<div><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
<div><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
<div><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<style>
div { padding: 5px; display: inline-block; }
.vlr { writing-mode: vertical-lr; text-orientation: sideways; }
.vrl { writing-mode: vertical-rl; text-orientation: sideways; }
.slr { writing-mode: sideways-lr; }
.srl { writing-mode: sideways-rl; }
span { display: inline-block; block-size: 2em; vertical-align: middle; }
span:nth-child(1) { background: red; inline-size: 1em; }
span:nth-child(2) { background: orange; inline-size: 1.1em; }
span:nth-child(3) { background: yellow; inline-size: 1.3em; }
span:nth-child(4) { background: green; inline-size: 1.5em; }
span:nth-child(5) { background: blue; inline-size: 1.7em; }
span:nth-child(6) { background: indigo; inline-size: 1.9em; }
span:nth-child(7) { background: violet; inline-size: 2em; }
</style>
</head>
<body>
<p>All four columns should look the same:
<div dir=ltr class="vrl"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
<div dir=ltr class="vlr"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
<div dir=ltr class="srl"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
<div dir=rtl class="slr"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<style>
div { padding: 5px; display: inline-block; }
span { display: block; width: 2em; }
span:nth-child(7) { background: red; height: 1em; }
span:nth-child(6) { background: orange; height: 1.1em; }
span:nth-child(5) { background: yellow; height: 1.3em; }
span:nth-child(4) { background: green; height: 1.5em; }
span:nth-child(3) { background: blue; height: 1.7em; }
span:nth-child(2) { background: indigo; height: 1.9em; }
span:nth-child(1) { background: violet; height: 2em; }
</style>
</head>
<body>
<p>All four columns should look the same:
<div><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
<div><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
<div><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
<div><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>

Some files were not shown because too many files have changed in this diff Show More