From de99f782842c83eb66464f90912f7095ab8c5109 Mon Sep 17 00:00:00 2001 From: "Kearwood (Kip) Gilbert" Date: Tue, 22 Apr 2014 15:30:00 +0200 Subject: [PATCH 01/40] Bug 920688 - Remove FIXME comment from StickyScrollContainer::ComputeStickyLimits. r=dbaron - The condition described in the FIXME comment is already handled by GetNearestBlockContainer in nsFrame.cpp (helper for nsIFrame::GetContainingBlock). --- layout/generic/StickyScrollContainer.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/layout/generic/StickyScrollContainer.cpp b/layout/generic/StickyScrollContainer.cpp index 5eb5c07ebcde..ec30fa9aa216 100644 --- a/layout/generic/StickyScrollContainer.cpp +++ b/layout/generic/StickyScrollContainer.cpp @@ -181,11 +181,6 @@ StickyScrollContainer::ComputeStickyLimits(nsIFrame* aFrame, nsRect* aStick, } nsIFrame* scrolledFrame = mScrollFrame->GetScrolledFrame(); - // FIXME (Bug 920688): cbFrame isn't quite right if we're dealing - // with a block-in-inline split whose first part is a block. We - // probably want the first in flow of the containing block of the - // first inline part. (Or maybe those block-in-inline split pieces - // are never a containing block, and we're ok?) nsIFrame* cbFrame = aFrame->GetContainingBlock(); NS_ASSERTION(cbFrame == scrolledFrame || nsLayoutUtils::IsProperAncestorFrame(scrolledFrame, cbFrame), From ff8f1e047cf3de5c3728a6b47aefc3aed9ac0fe1 Mon Sep 17 00:00:00 2001 From: Jed Parsons Date: Tue, 22 Apr 2014 14:16:39 -0700 Subject: [PATCH 02/40] Bug 982460 - privileged-request-sans-event. r=spenrose --- dom/identity/nsDOMIdentity.js | 11 +++++------ .../tests/mochitest/file_syntheticEvents.html | 3 ++- .../tests/mochitest/test_syntheticEvents.html | 7 ++----- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/dom/identity/nsDOMIdentity.js b/dom/identity/nsDOMIdentity.js index 73cf6c93844b..203b7890d30e 100644 --- a/dom/identity/nsDOMIdentity.js +++ b/dom/identity/nsDOMIdentity.js @@ -169,14 +169,13 @@ nsDOMIdentity.prototype = { let message = this.DOMIdentityMessage(aOptions); // We permit calling of request() outside of a user input handler only when - // we are handling the (deprecated) get() or getVerifiedEmail() calls, - // which make use of an RP context marked as _internal, or when a certified - // app is calling. - // - // XXX Bug 982460 - grant the same privilege to packaged apps + // a certified or privileged app is calling, or when we are handling the + // (deprecated) get() or getVerifiedEmail() calls, which make use of an RP + // context marked as _internal. if (!aOptions._internal && - this._appStatus !== Ci.nsIPrincipal.APP_STATUS_CERTIFIED) { + this._appStatus !== Ci.nsIPrincipal.APP_STATUS_CERTIFIED && + this._appStatus !== Ci.nsIPrincipal.APP_STATUS_PRIVILEGED) { // If the caller is not special in one of those ways, see if the user has // preffed on 'syntheticEventsOk' (useful for testing); otherwise, if diff --git a/dom/identity/tests/mochitest/file_syntheticEvents.html b/dom/identity/tests/mochitest/file_syntheticEvents.html index 84c85128aeb8..58cd005f5cca 100644 --- a/dom/identity/tests/mochitest/file_syntheticEvents.html +++ b/dom/identity/tests/mochitest/file_syntheticEvents.html @@ -7,7 +7,8 @@ diff --git a/dom/identity/tests/mochitest/test_syntheticEvents.html b/dom/identity/tests/mochitest/test_syntheticEvents.html index 2e01deac6bd8..899eddc76a6e 100644 --- a/dom/identity/tests/mochitest/test_syntheticEvents.html +++ b/dom/identity/tests/mochitest/test_syntheticEvents.html @@ -94,16 +94,13 @@ let apps = [ }, }, { - title: "a privileged app, which may not use synthetic events (until bug 982460 lands)", + title: "a privileged app, which may use synthetic events", manifest: "https://example.com/manifest_priv.webapp", origin: "https://example.com", uri: "https://example.com/chrome/dom/identity/tests/mochitest/file_syntheticEvents.html", wantIssuer: "firefox-accounts", expected: { - success: false, - errors: [ - "ERROR_REQUEST_WHILE_NOT_HANDLING_USER_INPUT", - ], + success: true, }, }, { From 2ce5fd2459932505eaeab33c7742c2af29843fe4 Mon Sep 17 00:00:00 2001 From: Benjamin Chen Date: Wed, 23 Apr 2014 10:32:46 +0800 Subject: [PATCH 03/40] Bug 994557 - part1:fix formatting, typo, 80 characters. r=rillian --- content/media/webm/EbmlComposer.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/content/media/webm/EbmlComposer.cpp b/content/media/webm/EbmlComposer.cpp index 6059563bfb5d..8642084249b3 100644 --- a/content/media/webm/EbmlComposer.cpp +++ b/content/media/webm/EbmlComposer.cpp @@ -31,7 +31,8 @@ void EbmlComposer::GenerateHeader() Ebml_StartSubElement(&ebml, &segEbmlLoc, Segment); { Ebml_StartSubElement(&ebml, &ebmlLocseg, SeekHead); - // Todo: We don't know the exact sizes of encoded data and ignore this section. + // Todo: We don't know the exact sizes of encoded data and + // ignore this section. Ebml_EndSubElement(&ebml, &ebmlLocseg); writeSegmentInformation(&ebml, &ebmlLoc, TIME_CODE_SCALE, 0); { @@ -54,7 +55,8 @@ void EbmlComposer::GenerateHeader() Ebml_EndSubElement(&ebml, &trackLoc); } } - // The Recording length is unknow and ignore write the whole Segment element size + // The Recording length is unknown and + // ignore write the whole Segment element size } MOZ_ASSERT(ebml.offset <= DEFAULT_HEADER_SIZE + mCodecPrivateData.Length(), "write more data > EBML_BUFFER_SIZE"); @@ -67,7 +69,7 @@ void EbmlComposer::FinishCluster() { MOZ_ASSERT(mClusterLengthLoc > 0 ); MOZ_ASSERT(mClusterHeaderIndex > 0); - for (uint32_t i = 0; i < mClusterBuffs.Length(); i ++ ) { + for (uint32_t i = 0; i < mClusterBuffs.Length(); i++) { mClusterCanFlushBuffs.AppendElement()->SwapElements(mClusterBuffs[i]); } mClusterBuffs.Clear(); @@ -98,7 +100,8 @@ EbmlComposer::WriteSimpleBlock(EncodedFrame* aFrame) if (aFrame->GetFrameType() == EncodedFrame::FrameType::VP8_I_FRAME) { EbmlLoc ebmlLoc; Ebml_StartSubElement(&ebml, &ebmlLoc, Cluster); - mClusterHeaderIndex = mClusterBuffs.Length() - 1; // current cluster header array index + // current cluster header array index + mClusterHeaderIndex = mClusterBuffs.Length() - 1; mClusterLengthLoc = ebmlLoc.offset; if (aFrame->GetFrameType() != EncodedFrame::FrameType::VORBIS_AUDIO_FRAME) { mClusterTimecode = aFrame->GetTimeStamp() / PR_USEC_PER_MSEC; @@ -107,7 +110,8 @@ EbmlComposer::WriteSimpleBlock(EncodedFrame* aFrame) } if (aFrame->GetFrameType() != EncodedFrame::FrameType::VORBIS_AUDIO_FRAME) { - short timeCode = aFrame->GetTimeStamp() / PR_USEC_PER_MSEC - mClusterTimecode; + short timeCode = aFrame->GetTimeStamp() / PR_USEC_PER_MSEC + - mClusterTimecode; writeSimpleBlock(&ebml, 0x1, timeCode, aFrame->GetFrameType() == EncodedFrame::FrameType::VP8_I_FRAME, 0, 0, (unsigned char*)aFrame->GetFrameData().Elements(), @@ -117,7 +121,8 @@ EbmlComposer::WriteSimpleBlock(EncodedFrame* aFrame) 0, 0, (unsigned char*)aFrame->GetFrameData().Elements(), aFrame->GetFrameData().Length()); } - MOZ_ASSERT(ebml.offset <= DEFAULT_HEADER_SIZE + aFrame->GetFrameData().Length(), + MOZ_ASSERT(ebml.offset <= DEFAULT_HEADER_SIZE + + aFrame->GetFrameData().Length(), "write more data > EBML_BUFFER_SIZE"); mClusterBuffs.LastElement().SetLength(ebml.offset); } @@ -159,7 +164,7 @@ EbmlComposer::ExtractBuffer(nsTArray >* aDestBufs, FinishCluster(); } // aDestBufs may have some element - for (uint32_t i = 0; i < mClusterCanFlushBuffs.Length(); i ++ ) { + for (uint32_t i = 0; i < mClusterCanFlushBuffs.Length(); i++) { aDestBufs->AppendElement()->SwapElements(mClusterCanFlushBuffs[i]); } mClusterCanFlushBuffs.Clear(); From 1cb73ec3734363f5851503936faf1317607cbf59 Mon Sep 17 00:00:00 2001 From: Benjamin Chen Date: Wed, 23 Apr 2014 12:04:27 +0800 Subject: [PATCH 04/40] Bug 994557 - part2: 1. fix bug in finishCluster function. 2. Can flush metadata only. 3. Ensure the keyframe is placed at the beginning of cluster. r=rillian --- content/media/webm/EbmlComposer.cpp | 67 ++++++++++++++++++++--------- content/media/webm/EbmlComposer.h | 12 +++++- 2 files changed, 58 insertions(+), 21 deletions(-) diff --git a/content/media/webm/EbmlComposer.cpp b/content/media/webm/EbmlComposer.cpp index 8642084249b3..af19a0166350 100644 --- a/content/media/webm/EbmlComposer.cpp +++ b/content/media/webm/EbmlComposer.cpp @@ -60,27 +60,47 @@ void EbmlComposer::GenerateHeader() } MOZ_ASSERT(ebml.offset <= DEFAULT_HEADER_SIZE + mCodecPrivateData.Length(), "write more data > EBML_BUFFER_SIZE"); - mClusterBuffs.AppendElement(); - mClusterBuffs.LastElement().SetLength(ebml.offset); - memcpy(mClusterBuffs.LastElement().Elements(), ebml.buf, ebml.offset); + auto block = mClusterBuffs.AppendElement(); + block->SetLength(ebml.offset); + memcpy(block->Elements(), ebml.buf, ebml.offset); + mFlushState |= FLUSH_METADATA; +} + +void EbmlComposer::FinishMetadata() +{ + if (mFlushState & FLUSH_METADATA) { + // We don't remove the first element of mClusterBuffs because the + // |mClusterHeaderIndex| may have value. + mClusterCanFlushBuffs.AppendElement()->SwapElements(mClusterBuffs[0]); + mFlushState &= ~FLUSH_METADATA; + } } void EbmlComposer::FinishCluster() { - MOZ_ASSERT(mClusterLengthLoc > 0 ); - MOZ_ASSERT(mClusterHeaderIndex > 0); - for (uint32_t i = 0; i < mClusterBuffs.Length(); i++) { - mClusterCanFlushBuffs.AppendElement()->SwapElements(mClusterBuffs[i]); + FinishMetadata(); + if (!(mFlushState & FLUSH_CLUSTER)) { + // No completed cluster available. + return; } - mClusterBuffs.Clear(); + + MOZ_ASSERT(mClusterLengthLoc > 0); EbmlGlobal ebml; EbmlLoc ebmlLoc; ebmlLoc.offset = mClusterLengthLoc; - ebml.offset = mClusterCanFlushBuffs[mClusterHeaderIndex].Length(); - ebml.buf = mClusterCanFlushBuffs[mClusterHeaderIndex].Elements(); + ebml.offset = mClusterBuffs[mClusterHeaderIndex].Length(); + ebml.buf = mClusterBuffs[mClusterHeaderIndex].Elements(); Ebml_EndSubElement(&ebml, &ebmlLoc); + // Move the mClusterBuffs data from mClusterHeaderIndex that we can skip + // the metadata and the rest P-frames after ContainerWriter::FLUSH_NEEDED. + for (uint32_t i = mClusterHeaderIndex; i < mClusterBuffs.Length(); i++) { + mClusterCanFlushBuffs.AppendElement()->SwapElements(mClusterBuffs[i]); + } + mClusterHeaderIndex = 0; mClusterLengthLoc = 0; + mClusterBuffs.Clear(); + mFlushState &= ~FLUSH_CLUSTER; } void @@ -89,24 +109,24 @@ EbmlComposer::WriteSimpleBlock(EncodedFrame* aFrame) EbmlGlobal ebml; ebml.offset = 0; - if (aFrame->GetFrameType() == EncodedFrame::FrameType::VP8_I_FRAME && mClusterHeaderIndex > 0) { + if (aFrame->GetFrameType() == EncodedFrame::FrameType::VP8_I_FRAME) { FinishCluster(); } - mClusterBuffs.AppendElement(); - mClusterBuffs.LastElement().SetLength(aFrame->GetFrameData().Length() + DEFAULT_HEADER_SIZE); - ebml.buf = mClusterBuffs.LastElement().Elements(); + auto block = mClusterBuffs.AppendElement(); + block->SetLength(aFrame->GetFrameData().Length() + DEFAULT_HEADER_SIZE); + ebml.buf = block->Elements(); if (aFrame->GetFrameType() == EncodedFrame::FrameType::VP8_I_FRAME) { EbmlLoc ebmlLoc; Ebml_StartSubElement(&ebml, &ebmlLoc, Cluster); + MOZ_ASSERT(mClusterBuffs.Length() > 0); // current cluster header array index mClusterHeaderIndex = mClusterBuffs.Length() - 1; mClusterLengthLoc = ebmlLoc.offset; - if (aFrame->GetFrameType() != EncodedFrame::FrameType::VORBIS_AUDIO_FRAME) { - mClusterTimecode = aFrame->GetTimeStamp() / PR_USEC_PER_MSEC; - } + mClusterTimecode = aFrame->GetTimeStamp() / PR_USEC_PER_MSEC; Ebml_SerializeUnsigned(&ebml, Timecode, mClusterTimecode); + mFlushState |= FLUSH_CLUSTER; } if (aFrame->GetFrameType() != EncodedFrame::FrameType::VORBIS_AUDIO_FRAME) { @@ -124,7 +144,7 @@ EbmlComposer::WriteSimpleBlock(EncodedFrame* aFrame) MOZ_ASSERT(ebml.offset <= DEFAULT_HEADER_SIZE + aFrame->GetFrameData().Length(), "write more data > EBML_BUFFER_SIZE"); - mClusterBuffs.LastElement().SetLength(ebml.offset); + block->SetLength(ebml.offset); } void @@ -160,7 +180,13 @@ void EbmlComposer::ExtractBuffer(nsTArray >* aDestBufs, uint32_t aFlag) { - if ((aFlag & ContainerWriter::FLUSH_NEEDED) && mClusterHeaderIndex > 0) { + if ((aFlag & ContainerWriter::FLUSH_NEEDED) || + (aFlag & ContainerWriter::GET_HEADER)) + { + FinishMetadata(); + } + if (aFlag & ContainerWriter::FLUSH_NEEDED) + { FinishCluster(); } // aDestBufs may have some element @@ -171,7 +197,8 @@ EbmlComposer::ExtractBuffer(nsTArray >* aDestBufs, } EbmlComposer::EbmlComposer() - : mClusterHeaderIndex(0) + : mFlushState(FLUSH_NONE) + , mClusterHeaderIndex(0) , mClusterLengthLoc(0) , mClusterTimecode(0) , mWidth(0) diff --git a/content/media/webm/EbmlComposer.h b/content/media/webm/EbmlComposer.h index 8096fd5ca937..ac7446e12320 100644 --- a/content/media/webm/EbmlComposer.h +++ b/content/media/webm/EbmlComposer.h @@ -46,13 +46,23 @@ public: void ExtractBuffer(nsTArray >* aDestBufs, uint32_t aFlag = 0); private: + // Move the metadata data to mClusterCanFlushBuffs. + void FinishMetadata(); // Close current cluster and move data to mClusterCanFlushBuffs. void FinishCluster(); // The temporary storage for cluster data. nsTArray > mClusterBuffs; // The storage which contain valid cluster data. nsTArray > mClusterCanFlushBuffs; - // Indicate the header index in mClusterBuffs. + + // Indicate the data types in mClusterBuffs. + enum { + FLUSH_NONE = 0, + FLUSH_METADATA = 1 << 0, + FLUSH_CLUSTER = 1 << 1 + }; + uint32_t mFlushState; + // Indicate the cluster header index in mClusterBuffs. uint32_t mClusterHeaderIndex; // The cluster length position. uint64_t mClusterLengthLoc; From fa142a758420da33a1163cfbfbf0f5b019bbf831 Mon Sep 17 00:00:00 2001 From: Cosmin Malutan Date: Wed, 23 Apr 2014 10:16:02 +0200 Subject: [PATCH 05/40] Bug 992139 - [mozversion] Enhance mozversion to return application_display_name. r=hskupin --- testing/mozbase/mozversion/mozversion/mozversion.py | 6 +++++- testing/mozbase/mozversion/tests/test_binary.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/testing/mozbase/mozversion/mozversion/mozversion.py b/testing/mozbase/mozversion/mozversion/mozversion.py index f383778c811e..e6d2fff8e755 100644 --- a/testing/mozbase/mozversion/mozversion/mozversion.py +++ b/testing/mozbase/mozversion/mozversion/mozversion.py @@ -43,7 +43,7 @@ class Version(mozlog.LoggingMixin): config_file = os.path.join(config_path, '%s.ini' % filename) if os.path.exists(config_file): config.read(config_file) - name_map = {'CodeName': 'code_name', + name_map = {'CodeName': 'display_name', 'SourceRepository': 'repository', 'SourceStamp': 'changeset'} for key in ('BuildID', 'Name', 'CodeName', 'Version', @@ -51,6 +51,10 @@ class Version(mozlog.LoggingMixin): name = name_map.get(key, key).lower() self._info['%s_%s' % (filename, name)] = config.has_option( section, key) and config.get(section, key) or None + + if not self._info.get('application_display_name'): + self._info['application_display_name'] = \ + self._info.get('application_name') else: self.warn('Unable to find %s' % config_file) diff --git a/testing/mozbase/mozversion/tests/test_binary.py b/testing/mozbase/mozversion/tests/test_binary.py index 9369268bd707..57b9cf6022ad 100644 --- a/testing/mozbase/mozversion/tests/test_binary.py +++ b/testing/mozbase/mozversion/tests/test_binary.py @@ -69,7 +69,7 @@ SourceRepository = PlatformSourceRepo def _check_version(self, version): self.assertEqual(version.get('application_name'), 'AppName') - self.assertEqual(version.get('application_code_name'), 'AppCodeName') + self.assertEqual(version.get('application_display_name'), 'AppCodeName') self.assertEqual(version.get('application_version'), 'AppVersion') self.assertEqual(version.get('application_buildid'), 'AppBuildID') self.assertEqual( From ad59de6573f4f22d6d02c5bf860eef8b19310a95 Mon Sep 17 00:00:00 2001 From: JW Wang Date: Wed, 23 Apr 2014 05:29:04 -0400 Subject: [PATCH 06/40] Bug 998168 - add decoder pointer to the log message of MediaDecoderStateMachine/MediaDecoder for debugging. r=cpearce --- content/media/MediaDecoder.cpp | 24 ++-- content/media/MediaDecoderStateMachine.cpp | 155 ++++++++++----------- 2 files changed, 87 insertions(+), 92 deletions(-) diff --git a/content/media/MediaDecoder.cpp b/content/media/MediaDecoder.cpp index a51e09871b14..1f062c7f772a 100644 --- a/content/media/MediaDecoder.cpp +++ b/content/media/MediaDecoder.cpp @@ -48,11 +48,15 @@ static const uint32_t STALL_MS = 3000; // fluctuating bitrates. static const int64_t CAN_PLAY_THROUGH_MARGIN = 1; +// avoid redefined macro in unified build +#undef DECODER_LOG + #ifdef PR_LOGGING PRLogModuleInfo* gMediaDecoderLog; -#define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg) +#define DECODER_LOG(type, msg, ...) \ + PR_LOG(gMediaDecoderLog, type, ("Decoder=%p " msg, this, ##__VA_ARGS__)) #else -#define DECODER_LOG(type, msg) +#define DECODER_LOG(type, msg, ...) #endif class MediaMemoryTracker : public nsIMemoryReporter @@ -314,8 +318,7 @@ void MediaDecoder::RecreateDecodedStream(int64_t aStartTimeUSecs) { MOZ_ASSERT(NS_IsMainThread()); GetReentrantMonitor().AssertCurrentThreadIn(); - DECODER_LOG(PR_LOG_DEBUG, ("MediaDecoder::RecreateDecodedStream this=%p aStartTimeUSecs=%lld!", - this, (long long)aStartTimeUSecs)); + DECODER_LOG(PR_LOG_DEBUG, "RecreateDecodedStream aStartTimeUSecs=%lld!", aStartTimeUSecs); DestroyDecodedStream(); @@ -347,8 +350,7 @@ void MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded) { MOZ_ASSERT(NS_IsMainThread()); - DECODER_LOG(PR_LOG_DEBUG, ("MediaDecoder::AddOutputStream this=%p aStream=%p!", - this, aStream)); + DECODER_LOG(PR_LOG_DEBUG, "AddOutputStream aStream=%p!", aStream); { ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); @@ -509,7 +511,7 @@ nsresult MediaDecoder::OpenResource(nsIStreamListener** aStreamListener) nsresult rv = mResource->Open(aStreamListener); if (NS_FAILED(rv)) { - DECODER_LOG(PR_LOG_DEBUG, ("%p Failed to open stream!", this)); + DECODER_LOG(PR_LOG_WARNING, "Failed to open stream!"); return rv; } } @@ -526,7 +528,7 @@ nsresult MediaDecoder::Load(nsIStreamListener** aStreamListener, mDecoderStateMachine = CreateStateMachine(); if (!mDecoderStateMachine) { - DECODER_LOG(PR_LOG_DEBUG, ("%p Failed to create state machine!", this)); + DECODER_LOG(PR_LOG_WARNING, "Failed to create state machine!"); return NS_ERROR_FAILURE; } @@ -541,7 +543,7 @@ nsresult MediaDecoder::InitializeStateMachine(MediaDecoder* aCloneDonor) MediaDecoder* cloneDonor = static_cast(aCloneDonor); if (NS_FAILED(mDecoderStateMachine->Init(cloneDonor ? cloneDonor->mDecoderStateMachine : nullptr))) { - DECODER_LOG(PR_LOG_DEBUG, ("%p Failed to init state machine!", this)); + DECODER_LOG(PR_LOG_WARNING, "Failed to init state machine!"); return NS_ERROR_FAILURE; } { @@ -1233,7 +1235,7 @@ void MediaDecoder::DurationChanged() SetInfinite(mDuration == -1); if (mOwner && oldDuration != mDuration && !IsInfinite()) { - DECODER_LOG(PR_LOG_DEBUG, ("%p duration changed to %lld", this, mDuration)); + DECODER_LOG(PR_LOG_DEBUG, "Duration changed to %lld", mDuration); mOwner->DispatchEvent(NS_LITERAL_STRING("durationchange")); } } @@ -1799,3 +1801,5 @@ MediaMemoryTracker::~MediaMemoryTracker() } // namespace mozilla +// avoid redefined macro in unified build +#undef DECODER_LOG diff --git a/content/media/MediaDecoderStateMachine.cpp b/content/media/MediaDecoderStateMachine.cpp index d7c7d49d6ff1..5847699796c4 100644 --- a/content/media/MediaDecoderStateMachine.cpp +++ b/content/media/MediaDecoderStateMachine.cpp @@ -43,11 +43,23 @@ using namespace mozilla::layers; using namespace mozilla::dom; using namespace mozilla::gfx; +// avoid redefined macro in unified build +#undef DECODER_LOG +#undef VERBOSE_LOG + #ifdef PR_LOGGING extern PRLogModuleInfo* gMediaDecoderLog; -#define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg) +#define DECODER_LOG(type, msg, ...) \ + PR_LOG(gMediaDecoderLog, type, ("Decoder=%p " msg, mDecoder.get(), ##__VA_ARGS__)) +#define VERBOSE_LOG(msg, ...) \ + PR_BEGIN_MACRO \ + if (!PR_GetEnv("MOZ_QUIET")) { \ + DECODER_LOG(PR_LOG_DEBUG, msg, ##__VA_ARGS__); \ + } \ + PR_END_MACRO #else -#define DECODER_LOG(type, msg) +#define DECODER_LOG(type, msg, ...) +#define VERBOSE_LOG(msg, ...) #endif // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to @@ -299,8 +311,8 @@ void MediaDecoderStateMachine::SendStreamAudio(AudioData* aAudio, return; if (audioWrittenOffset.value() < frameOffset.value()) { // Write silence to catch up - DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder writing %d frames of silence to MediaStream", - mDecoder.get(), int32_t(frameOffset.value() - audioWrittenOffset.value()))); + VERBOSE_LOG("writing %d frames of silence to MediaStream", + int32_t(frameOffset.value() - audioWrittenOffset.value())); AudioSegment silence; silence.InsertNullDataAtStart(frameOffset.value() - audioWrittenOffset.value()); aStream->mAudioFramesWritten += silence.GetDuration(); @@ -329,8 +341,8 @@ void MediaDecoderStateMachine::SendStreamAudio(AudioData* aAudio, channels.AppendElement(bufferData + i*aAudio->mFrames + offset); } aOutput->AppendFrames(buffer.forget(), channels, aAudio->mFrames); - DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder writing %d frames of data to MediaStream for AudioData at %lld", - mDecoder.get(), aAudio->mFrames - int32_t(offset), aAudio->mTime)); + VERBOSE_LOG("writing %d frames of data to MediaStream for AudioData at %lld", + aAudio->mFrames - int32_t(offset), aAudio->mTime); aStream->mAudioFramesWritten += aAudio->mFrames - int32_t(offset); } @@ -421,9 +433,8 @@ void MediaDecoderStateMachine::SendStreamData() for (uint32_t i = 0; i < video.Length(); ++i) { VideoData* v = video[i]; if (stream->mNextVideoTime < v->mTime) { - DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder writing last video to MediaStream %p for %lldus", - mDecoder.get(), mediaStream, - v->mTime - stream->mNextVideoTime)); + VERBOSE_LOG("writing last video to MediaStream %p for %lldus", + mediaStream, v->mTime - stream->mNextVideoTime); // Write last video frame to catch up. mLastVideoImage can be null here // which is fine, it just means there's no video. WriteVideoToMediaStream(stream->mLastVideoImage, @@ -432,9 +443,8 @@ void MediaDecoderStateMachine::SendStreamData() stream->mNextVideoTime = v->mTime; } if (stream->mNextVideoTime < v->GetEndTime()) { - DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder writing video frame %lldus to MediaStream %p for %lldus", - mDecoder.get(), v->mTime, mediaStream, - v->GetEndTime() - stream->mNextVideoTime)); + VERBOSE_LOG("writing video frame %lldus to MediaStream %p for %lldus", + v->mTime, mediaStream, v->GetEndTime() - stream->mNextVideoTime); WriteVideoToMediaStream(v->mImage, v->GetEndTime() - stream->mNextVideoTime, v->mDisplay, &output); @@ -442,8 +452,8 @@ void MediaDecoderStateMachine::SendStreamData() stream->mLastVideoImage = v->mImage; stream->mLastVideoImageDisplaySize = v->mDisplay; } else { - DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder skipping writing video frame %lldus (end %lldus) to MediaStream", - mDecoder.get(), v->mTime, v->GetEndTime())); + VERBOSE_LOG("skipping writing video frame %lldus (end %lldus) to MediaStream", + v->mTime, v->GetEndTime()); } } if (output.GetDuration() > 0) { @@ -598,7 +608,7 @@ MediaDecoderStateMachine::DecodeVideo() !HasLowUndecodedData()) { mSkipToNextKeyFrame = true; - DECODER_LOG(PR_LOG_DEBUG, ("%p Skipping video decode to the next keyframe", mDecoder.get())); + DECODER_LOG(PR_LOG_DEBUG, "Skipping video decode to the next keyframe"); } // Time the video decode, so that if it's slow, we can increase our low @@ -625,9 +635,8 @@ MediaDecoderStateMachine::DecodeVideo() std::min(THRESHOLD_FACTOR * DurationToUsecs(decodeTime), AMPLE_AUDIO_USECS); mAmpleAudioThresholdUsecs = std::max(THRESHOLD_FACTOR * mLowAudioThresholdUsecs, mAmpleAudioThresholdUsecs); - DECODER_LOG(PR_LOG_DEBUG, - ("Slow video decode, set mLowAudioThresholdUsecs=%lld mAmpleAudioThresholdUsecs=%lld", - mLowAudioThresholdUsecs, mAmpleAudioThresholdUsecs)); + DECODER_LOG(PR_LOG_DEBUG, "Slow video decode, set mLowAudioThresholdUsecs=%lld mAmpleAudioThresholdUsecs=%lld", + mLowAudioThresholdUsecs, mAmpleAudioThresholdUsecs); } SendStreamData(); @@ -715,9 +724,8 @@ MediaDecoderStateMachine::CheckIfDecodeComplete() DispatchDecodeTasksIfNeeded(); ScheduleStateMachine(); } - DECODER_LOG(PR_LOG_DEBUG, - ("%p CheckIfDecodeComplete %scompleted", mDecoder.get(), - ((mState == DECODER_STATE_COMPLETED) ? "" : "NOT "))); + DECODER_LOG(PR_LOG_DEBUG, "CheckIfDecodeComplete %scompleted", + ((mState == DECODER_STATE_COMPLETED) ? "" : "NOT ")); } bool MediaDecoderStateMachine::IsPlaying() @@ -753,7 +761,7 @@ static void WriteSilence(AudioStream* aStream, uint32_t aFrames) void MediaDecoderStateMachine::AudioLoop() { NS_ASSERTION(OnAudioThread(), "Should be on audio thread."); - DECODER_LOG(PR_LOG_DEBUG, ("%p Begun audio thread/loop", mDecoder.get())); + DECODER_LOG(PR_LOG_DEBUG, "Begun audio thread/loop"); int64_t audioDuration = 0; int64_t audioStartTime = -1; uint32_t channels, rate; @@ -891,8 +899,7 @@ void MediaDecoderStateMachine::AudioLoop() // hardware so that the next audio chunk begins playback at the correct // time. missingFrames = std::min(UINT32_MAX, missingFrames.value()); - DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder playing %d frames of silence", - mDecoder.get(), int32_t(missingFrames.value()))); + VERBOSE_LOG("playing %d frames of silence", int32_t(missingFrames.value())); framesWritten = PlaySilence(static_cast(missingFrames.value()), channels, playedFrames.value()); } else { @@ -945,7 +952,7 @@ void MediaDecoderStateMachine::AudioLoop() } } } - DECODER_LOG(PR_LOG_DEBUG, ("%p Reached audio stream end.", mDecoder.get())); + DECODER_LOG(PR_LOG_DEBUG, "Reached audio stream end."); { // Must hold lock while shutting down and anulling the audio stream to prevent // state machine thread trying to use it while we're destroying it. @@ -960,7 +967,7 @@ void MediaDecoderStateMachine::AudioLoop() } } - DECODER_LOG(PR_LOG_DEBUG, ("%p Audio stream finished playing, audio thread exit", mDecoder.get())); + DECODER_LOG(PR_LOG_DEBUG, "Audio stream finished playing, audio thread exit"); } uint32_t MediaDecoderStateMachine::PlaySilence(uint32_t aFrames, @@ -991,10 +998,8 @@ uint32_t MediaDecoderStateMachine::PlayFromAudioQueue(uint64_t aFrameOffset, } int64_t offset = -1; uint32_t frames = 0; - if (!PR_GetEnv("MOZ_QUIET")) { - DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder playing %d frames of data to stream for AudioData at %lld", - mDecoder.get(), audio->mFrames, audio->mTime)); - } + VERBOSE_LOG("playing %d frames of data to stream for AudioData at %lld", + audio->mFrames, audio->mTime); mAudioStream->Write(audio->mAudioData, audio->mFrames); @@ -1045,7 +1050,7 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoderStateMachine* aCloneDonor) void MediaDecoderStateMachine::StopPlayback() { - DECODER_LOG(PR_LOG_DEBUG, ("%p StopPlayback()", mDecoder.get())); + DECODER_LOG(PR_LOG_DEBUG, "StopPlayback()"); AssertCurrentThreadInMonitor(); @@ -1088,7 +1093,7 @@ int64_t MediaDecoderStateMachine::GetCurrentTimeViaMediaStreamSync() void MediaDecoderStateMachine::StartPlayback() { - DECODER_LOG(PR_LOG_DEBUG, ("%p StartPlayback()", mDecoder.get())); + DECODER_LOG(PR_LOG_DEBUG, "StartPlayback()"); NS_ASSERTION(!IsPlaying(), "Shouldn't be playing when StartPlayback() is called"); AssertCurrentThreadInMonitor(); @@ -1300,7 +1305,7 @@ void MediaDecoderStateMachine::Shutdown() // Change state before issuing shutdown request to threads so those // threads can start exiting cleanly during the Shutdown call. - DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state to SHUTDOWN", mDecoder.get())); + DECODER_LOG(PR_LOG_DEBUG, "Changed state to SHUTDOWN"); ScheduleStateMachine(); mState = DECODER_STATE_SHUTDOWN; mDecoder->GetReentrantMonitor().NotifyAll(); @@ -1368,7 +1373,7 @@ void MediaDecoderStateMachine::Play() // when the state machine notices the decoder's state change to PLAYING. ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); if (mState == DECODER_STATE_BUFFERING) { - DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state from BUFFERING to DECODING", mDecoder.get())); + DECODER_LOG(PR_LOG_DEBUG, "Changed state from BUFFERING to DECODING"); mState = DECODER_STATE_DECODING; mDecodeStartTime = TimeStamp::Now(); } @@ -1442,7 +1447,7 @@ void MediaDecoderStateMachine::Seek(const SeekTarget& aTarget) mSeekTarget = SeekTarget(seekTime, aTarget.mType); mBasePosition = seekTime - mStartTime; - DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state to SEEKING (to %ld)", mDecoder.get(), mSeekTarget.mTime)); + DECODER_LOG(PR_LOG_DEBUG, "Changed state to SEEKING (to %ld)", mSeekTarget.mTime); mState = DECODER_STATE_SEEKING; if (mDecoder->GetDecodedStream()) { mDecoder->RecreateDecodedStream(seekTime - mStartTime); @@ -1464,7 +1469,7 @@ void MediaDecoderStateMachine::StopAudioThread() mStopAudioThread = true; mDecoder->GetReentrantMonitor().NotifyAll(); if (mAudioThread) { - DECODER_LOG(PR_LOG_DEBUG, ("%p Shutdown audio thread", mDecoder.get())); + DECODER_LOG(PR_LOG_DEBUG, "Shutdown audio thread"); { ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); mAudioThread->Shutdown(); @@ -1512,10 +1517,9 @@ MediaDecoderStateMachine::SetReaderIdle() #ifdef PR_LOGGING { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - DECODER_LOG(PR_LOG_DEBUG, ("%p SetReaderIdle() audioQueue=%lld videoQueue=%lld", - mDecoder.get(), - GetDecodedAudioDuration(), - mReader->VideoQueue().Duration())); + DECODER_LOG(PR_LOG_DEBUG, "SetReaderIdle() audioQueue=%lld videoQueue=%lld", + GetDecodedAudioDuration(), + mReader->VideoQueue().Duration()); } #endif MOZ_ASSERT(OnDecodeThread()); @@ -1525,7 +1529,7 @@ MediaDecoderStateMachine::SetReaderIdle() void MediaDecoderStateMachine::SetReaderActive() { - DECODER_LOG(PR_LOG_DEBUG, ("%p SetReaderActive()", mDecoder.get())); + DECODER_LOG(PR_LOG_DEBUG, "SetReaderActive()"); MOZ_ASSERT(OnDecodeThread()); mReader->SetActive(); } @@ -1699,7 +1703,7 @@ MediaDecoderStateMachine::StartAudioThread() nullptr, MEDIA_THREAD_STACK_SIZE); if (NS_FAILED(rv)) { - DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state to SHUTDOWN because failed to create audio thread", mDecoder.get())); + DECODER_LOG(PR_LOG_WARNING, "Changed state to SHUTDOWN because failed to create audio thread"); mState = DECODER_STATE_SHUTDOWN; return rv; } @@ -1776,7 +1780,7 @@ MediaDecoderStateMachine::DecodeError() // Change state to shutdown before sending error report to MediaDecoder // and the HTMLMediaElement, so that our pipeline can start exiting // cleanly during the sync dispatch below. - DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state to SHUTDOWN", mDecoder.get())); + DECODER_LOG(PR_LOG_WARNING, "Decode error, changed state to SHUTDOWN"); ScheduleStateMachine(); mState = DECODER_STATE_SHUTDOWN; mDecoder->GetReentrantMonitor().NotifyAll(); @@ -1803,7 +1807,7 @@ MediaDecoderStateMachine::CallDecodeMetadata() return; } if (NS_FAILED(DecodeMetadata())) { - DECODER_LOG(PR_LOG_DEBUG, ("Decode metadata failed, shutting down decoder")); + DECODER_LOG(PR_LOG_WARNING, "Decode metadata failed, shutting down decoder"); DecodeError(); } } @@ -1812,7 +1816,7 @@ nsresult MediaDecoderStateMachine::DecodeMetadata() { AssertCurrentThreadInMonitor(); NS_ASSERTION(OnDecodeThread(), "Should be on decode thread."); - DECODER_LOG(PR_LOG_DEBUG, ("%p Decoding Media Headers", mDecoder.get())); + DECODER_LOG(PR_LOG_DEBUG, "Decoding Media Headers"); if (mState != DECODER_STATE_DECODING_METADATA) { return NS_ERROR_FAILURE; } @@ -1857,10 +1861,9 @@ nsresult MediaDecoderStateMachine::DecodeMetadata() "Active seekable media should have end time"); MOZ_ASSERT(!(mMediaSeekable && mTransportSeekable) || GetDuration() != -1, "Seekable media should have duration"); - DECODER_LOG(PR_LOG_DEBUG, ("%p Media goes from %lld to %lld (duration %lld)" - " transportSeekable=%d, mediaSeekable=%d", - mDecoder.get(), mStartTime, mEndTime, GetDuration(), - mTransportSeekable, mMediaSeekable)); + DECODER_LOG(PR_LOG_DEBUG, "Media goes from %lld to %lld (duration %lld) " + "transportSeekable=%d, mediaSeekable=%d", + mStartTime, mEndTime, GetDuration(), mTransportSeekable, mMediaSeekable); if (HasAudio() && !HasVideo()) { // We're playing audio only. We don't need to worry about slow video @@ -1892,7 +1895,7 @@ nsresult MediaDecoderStateMachine::DecodeMetadata() } if (mState == DECODER_STATE_DECODING_METADATA) { - DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state from DECODING_METADATA to DECODING", mDecoder.get())); + DECODER_LOG(PR_LOG_DEBUG, "Changed state from DECODING_METADATA to DECODING"); StartDecoding(); } @@ -2025,8 +2028,7 @@ void MediaDecoderStateMachine::DecodeSeek() // Seeked to end of media, move to COMPLETED state. Note we don't do // this if we're playing a live stream, since the end of media will advance // once we download more data! - DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lld) to COMPLETED", - mDecoder.get(), seekTime)); + DECODER_LOG(PR_LOG_DEBUG, "Changed state from SEEKING (to %lld) to COMPLETED", seekTime); stopEvent = NS_NewRunnableMethod(mDecoder, &MediaDecoder::SeekingStoppedAtEnd); // Explicitly set our state so we don't decode further, and so // we report playback ended to the media element. @@ -2035,8 +2037,7 @@ void MediaDecoderStateMachine::DecodeSeek() mIsVideoDecoding = false; DispatchDecodeTasksIfNeeded(); } else { - DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lld) to DECODING", - mDecoder.get(), seekTime)); + DECODER_LOG(PR_LOG_DEBUG, "Changed state from SEEKING (to %lld) to DECODING", seekTime); stopEvent = NS_NewRunnableMethod(mDecoder, &MediaDecoder::SeekingStopped); StartDecoding(); } @@ -2049,8 +2050,7 @@ void MediaDecoderStateMachine::DecodeSeek() } // Try to decode another frame to detect if we're at the end... - DECODER_LOG(PR_LOG_DEBUG, ("%p Seek completed, mCurrentFrameTime=%lld\n", - mDecoder.get(), mCurrentFrameTime)); + DECODER_LOG(PR_LOG_DEBUG, "Seek completed, mCurrentFrameTime=%lld", mCurrentFrameTime); { ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); @@ -2226,19 +2226,14 @@ nsresult MediaDecoderStateMachine::RunStateMachine() !mDecoder->IsDataCachedToEndOfResource() && !resource->IsSuspended()) { - DECODER_LOG(PR_LOG_DEBUG, - ("%p Buffering: wait %ds, timeout in %.3lfs %s", - mDecoder.get(), - mBufferingWait, - mBufferingWait - elapsed.ToSeconds(), - (mQuickBuffering ? "(quick exit)" : ""))); + DECODER_LOG(PR_LOG_DEBUG, "Buffering: wait %ds, timeout in %.3lfs %s", + mBufferingWait, mBufferingWait - elapsed.ToSeconds(), + (mQuickBuffering ? "(quick exit)" : "")); ScheduleStateMachine(USECS_PER_S); return NS_OK; } else { - DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state from BUFFERING to DECODING", mDecoder.get())); - DECODER_LOG(PR_LOG_DEBUG, ("%p Buffered for %.3lfs", - mDecoder.get(), - (now - mBufferingStart).ToSeconds())); + DECODER_LOG(PR_LOG_DEBUG, "Changed state from BUFFERING to DECODING"); + DECODER_LOG(PR_LOG_DEBUG, "Buffered for %.3lfs", (now - mBufferingStart).ToSeconds()); StartDecoding(); } @@ -2324,10 +2319,7 @@ void MediaDecoderStateMachine::RenderVideoFrame(VideoData* aData, return; } - if (!PR_GetEnv("MOZ_QUIET")) { - DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder playing video frame %lld", - mDecoder.get(), aData->mTime)); - } + VERBOSE_LOG("playing video frame %lld", aData->mTime); VideoFrameContainer* container = mDecoder->GetVideoFrameContainer(); if (container) { @@ -2438,12 +2430,9 @@ void MediaDecoderStateMachine::AdvanceFrame() mVideoFrameEndTime = frame->GetEndTime(); currentFrame = frame; #ifdef PR_LOGGING - if (!PR_GetEnv("MOZ_QUIET")) { - DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder discarding video frame %lld", mDecoder.get(), frame->mTime)); - if (droppedFrames++) { - DECODER_LOG(PR_LOG_DEBUG, ("%p Decoder discarding video frame %lld (%d so far)", - mDecoder.get(), frame->mTime, droppedFrames - 1)); - } + VERBOSE_LOG("discarding video frame %lld", frame->mTime); + if (droppedFrames++) { + VERBOSE_LOG("discarding video frame %lld (%d so far)", frame->mTime, droppedFrames-1); } #endif mReader->VideoQueue().PopFront(); @@ -2581,7 +2570,7 @@ VideoData* MediaDecoderStateMachine::FindStartTime() // first actual audio frame we have, we'll inject silence during playback // to ensure the audio starts at the correct time. mAudioStartTime = mStartTime; - DECODER_LOG(PR_LOG_DEBUG, ("%p Media start time is %lld", mDecoder.get(), mStartTime)); + DECODER_LOG(PR_LOG_DEBUG, "Media start time is %lld", mStartTime); return v; } @@ -2651,14 +2640,13 @@ void MediaDecoderStateMachine::StartBuffering() // the element we're buffering or not. UpdateReadyState(); mState = DECODER_STATE_BUFFERING; - DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state from DECODING to BUFFERING, decoded for %.3lfs", - mDecoder.get(), decodeDuration.ToSeconds())); + DECODER_LOG(PR_LOG_DEBUG, "Changed state from DECODING to BUFFERING, decoded for %.3lfs", + decodeDuration.ToSeconds()); #ifdef PR_LOGGING MediaDecoder::Statistics stats = mDecoder->GetStatistics(); - DECODER_LOG(PR_LOG_DEBUG, ("%p Playback rate: %.1lfKB/s%s download rate: %.1lfKB/s%s", - mDecoder.get(), + DECODER_LOG(PR_LOG_DEBUG, "Playback rate: %.1lfKB/s%s download rate: %.1lfKB/s%s", stats.mPlaybackRate/1024, stats.mPlaybackRateReliable ? "" : " (unreliable)", - stats.mDownloadRate/1024, stats.mDownloadRateReliable ? "" : " (unreliable)")); + stats.mDownloadRate/1024, stats.mDownloadRateReliable ? "" : " (unreliable)"); #endif } @@ -2827,3 +2815,6 @@ void MediaDecoderStateMachine::QueueMetadata(int64_t aPublishTime, } // namespace mozilla +// avoid redefined macro in unified build +#undef DECODER_LOG +#undef VERBOSE_LOG From 5bfcd08a49e59abd9abfe3ab02a2894c9c0c8c5e Mon Sep 17 00:00:00 2001 From: JW Wang Date: Wed, 23 Apr 2014 05:29:14 -0400 Subject: [PATCH 07/40] Bug 998168 - nsITimer functions should be only called in the event target thread of the timer. r=cpearce. --- content/media/MediaDecoderStateMachine.cpp | 79 ++++++++++++++++------ content/media/MediaDecoderStateMachine.h | 5 +- 2 files changed, 61 insertions(+), 23 deletions(-) diff --git a/content/media/MediaDecoderStateMachine.cpp b/content/media/MediaDecoderStateMachine.cpp index 5847699796c4..0b49a1643d55 100644 --- a/content/media/MediaDecoderStateMachine.cpp +++ b/content/media/MediaDecoderStateMachine.cpp @@ -207,7 +207,8 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder, mMinimizePreroll(false), mDecodeThreadWaiting(false), mRealTime(aRealTime), - mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED) + mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED), + mTimerId(0) { MOZ_COUNT_CTOR(MediaDecoderStateMachine); NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); @@ -247,9 +248,8 @@ MediaDecoderStateMachine::~MediaDecoderStateMachine() mDecodeTaskQueue = nullptr; } - if (mTimer) { - mTimer->Cancel(); - } + // No need to cancel the timer here for we've done that in + // TimeoutExpired() triggered by Shutdown() mTimer = nullptr; mReader = nullptr; @@ -2677,18 +2677,16 @@ nsresult MediaDecoderStateMachine::CallRunStateMachine() return res; } -static void TimeoutExpired(nsITimer *aTimer, void *aClosure) { - MediaDecoderStateMachine *machine = - static_cast(aClosure); - NS_ASSERTION(machine, "Must have been passed state machine"); - machine->TimeoutExpired(); -} - -void MediaDecoderStateMachine::TimeoutExpired() +nsresult MediaDecoderStateMachine::TimeoutExpired(int aTimerId) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); NS_ASSERTION(OnStateMachineThread(), "Must be on state machine thread"); - CallRunStateMachine(); + mTimer->Cancel(); + if (mTimerId == aTimerId) { + return CallRunStateMachine(); + } else { + return NS_OK; + } } void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder() { @@ -2697,6 +2695,26 @@ void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder() { DispatchVideoDecodeTaskIfNeeded(); } +class TimerEvent : public nsITimerCallback, public nsRunnable { + NS_DECL_THREADSAFE_ISUPPORTS +public: + TimerEvent(MediaDecoderStateMachine* aStateMachine, int aTimerId) + : mStateMachine(aStateMachine), mTimerId(aTimerId) {} + + NS_IMETHOD Run() MOZ_OVERRIDE { + return mStateMachine->TimeoutExpired(mTimerId); + } + + NS_IMETHOD Notify(nsITimer* aTimer) { + return mStateMachine->TimeoutExpired(mTimerId); + } +private: + const nsRefPtr mStateMachine; + int mTimerId; +}; + +NS_IMPL_ISUPPORTS2(TimerEvent, nsITimerCallback, nsIRunnable); + nsresult MediaDecoderStateMachine::ScheduleStateMachine(int64_t aUsecs) { AssertCurrentThreadInMonitor(); NS_ABORT_IF_FALSE(GetStateMachineThread(), @@ -2718,15 +2736,32 @@ nsresult MediaDecoderStateMachine::ScheduleStateMachine(int64_t aUsecs) { if (mRealTime && ms > 40) { ms = 40; } - mTimeout = timeout; - // Cancel existing timer if any since we are going to schedule a new one. - mTimer->Cancel(); - nsresult rv = mTimer->InitWithFuncCallback(mozilla::TimeoutExpired, - this, - ms, - nsITimer::TYPE_ONE_SHOT); - NS_ENSURE_SUCCESS(rv, rv); - return NS_OK; + + // Don't cancel the timer here for this function will be called from + // different threads. + + nsresult rv = NS_ERROR_FAILURE; + nsRefPtr event = new TimerEvent(this, mTimerId+1); + + if (ms == 0) { + // Dispatch a runnable to the state machine thread when delay is 0. + // It will has less latency than dispatching a runnable to the state + // machine thread which will then schedule a zero-delay timer. + rv = GetStateMachineThread()->Dispatch(event, NS_DISPATCH_NORMAL); + } else if (OnStateMachineThread()) { + rv = mTimer->InitWithCallback(event, ms, nsITimer::TYPE_ONE_SHOT); + } else { + MOZ_ASSERT(false, "non-zero delay timer should be only scheduled in state machine thread"); + } + + if (NS_SUCCEEDED(rv)) { + mTimeout = timeout; + ++mTimerId; + } else { + NS_WARNING("Failed to schedule state machine"); + } + + return rv; } bool MediaDecoderStateMachine::OnDecodeThread() const diff --git a/content/media/MediaDecoderStateMachine.h b/content/media/MediaDecoderStateMachine.h index b91f6da4fecd..61ee7883b0bf 100644 --- a/content/media/MediaDecoderStateMachine.h +++ b/content/media/MediaDecoderStateMachine.h @@ -307,7 +307,7 @@ public: nsresult ScheduleStateMachine(int64_t aUsecs = 0); // Timer function to implement ScheduleStateMachine(aUsecs). - void TimeoutExpired(); + nsresult TimeoutExpired(int aGeneration); // Set the media fragment end time. aEndTime is in microseconds. void SetFragmentEndTime(int64_t aEndTime); @@ -937,6 +937,9 @@ private: mozilla::MediaMetadataManager mMetadataManager; MediaDecoderOwner::NextFrameStatus mLastFrameStatus; + + // The id of timer tasks, used to ignore tasks that are scheduled previously. + int mTimerId; }; } // namespace mozilla; From ddce1750e2dc76d298b5a94ee01d979bef064fc9 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Wed, 23 Apr 2014 11:31:43 +0200 Subject: [PATCH 08/40] Bug 999358 - Fix MLambdaArrow to initialize the unused extended slot too. r=terrence --- js/src/jit/CodeGenerator.cpp | 7 +++++-- js/src/jsfun.h | 9 ++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index f3fa5873e4df..5310b206cde8 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -1012,9 +1012,12 @@ CodeGenerator::visitLambdaArrow(LLambdaArrow *lir) emitLambdaInit(output, scopeChain, info); - // Store the lexical |this| value. + // Initialize extended slots. Lexical |this| is stored in the first one. MOZ_ASSERT(info.flags & JSFunction::EXTENDED); - masm.storeValue(thisv, Address(output, FunctionExtended::offsetOfArrowThisSlot())); + static_assert(FunctionExtended::NUM_EXTENDED_SLOTS == 2, "All slots must be initialized"); + static_assert(FunctionExtended::ARROW_THIS_SLOT == 0, "|this| must be stored in first slot"); + masm.storeValue(thisv, Address(output, FunctionExtended::offsetOfExtendedSlot(0))); + masm.storeValue(UndefinedValue(), Address(output, FunctionExtended::offsetOfExtendedSlot(1))); masm.bind(ool->rejoin()); return true; diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 1c15c2af3653..7f7ea30be4f7 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -544,8 +544,15 @@ class FunctionExtended : public JSFunction public: static const unsigned NUM_EXTENDED_SLOTS = 2; + /* Arrow functions store their lexical |this| in the first extended slot. */ + static const unsigned ARROW_THIS_SLOT = 0; + + static inline size_t offsetOfExtendedSlot(unsigned which) { + MOZ_ASSERT(which < NUM_EXTENDED_SLOTS); + return offsetof(FunctionExtended, extendedSlots) + which * sizeof(HeapValue); + } static inline size_t offsetOfArrowThisSlot() { - return offsetof(FunctionExtended, extendedSlots) + 0 * sizeof(HeapValue); + return offsetOfExtendedSlot(ARROW_THIS_SLOT); } private: From f011b43abddfbcf22cf44d4b0ed1c51c23f89a33 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Wed, 23 Apr 2014 11:47:19 +0200 Subject: [PATCH 09/40] Bug 997735 - Add a test. r=roc --- .../invalidation/filter-userspace-offset.svg | 156 ++++++++++++++++++ layout/reftests/invalidation/reftest.list | 30 ++++ 2 files changed, 186 insertions(+) create mode 100644 layout/reftests/invalidation/filter-userspace-offset.svg diff --git a/layout/reftests/invalidation/filter-userspace-offset.svg b/layout/reftests/invalidation/filter-userspace-offset.svg new file mode 100644 index 000000000000..2f0581b4d682 --- /dev/null +++ b/layout/reftests/invalidation/filter-userspace-offset.svg @@ -0,0 +1,156 @@ + + Filters and offsets, user space origins, invalidation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/layout/reftests/invalidation/reftest.list b/layout/reftests/invalidation/reftest.list index 70057ed5573d..8c53fd5e1dae 100644 --- a/layout/reftests/invalidation/reftest.list +++ b/layout/reftests/invalidation/reftest.list @@ -8,3 +8,33 @@ skip-if(B2G&&browserIsRemote) == 543681-1.html 543681-1-ref.html pref(layout.animated-image-layers.enabled,true) == test-animated-image-layers.html test-animated-image-layers-ref.html pref(layout.animated-image-layers.enabled,true) == test-animated-image-layers-background.html test-animated-image-layers-ref.html == box-shadow-border-radius.html box-shadow-border-radius-ref.html +== filter-userspace-offset.svg?offsetContainer=rect filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=use filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=innerSVG filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=foreignObject filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=rect&filter=flood-boundingBox filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=use&filter=flood-boundingBox filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=innerSVG&filter=flood-boundingBox filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=foreignObject&filter=flood-boundingBox filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=rect&filter=matrix-boundingBox filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=use&filter=matrix-boundingBox filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=innerSVG&filter=matrix-boundingBox filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=foreignObject&filter=matrix-boundingBox filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=rect&filter=flood-userSpace-at100 filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=use&filter=flood-userSpace-atZero filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=innerSVG&filter=flood-userSpace-atZero filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=foreignObject&filter=flood-userSpace-at100 filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=rect&filter=matrix-userSpace-at100 filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=use&filter=matrix-userSpace-atZero filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=innerSVG&filter=matrix-userSpace-atZero filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=foreignObject&filter=matrix-userSpace-at100 filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=rect&mask=boundingBox filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=use&mask=boundingBox filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=innerSVG&mask=boundingBox filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=foreignObject&mask=boundingBox filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=rect&mask=userSpace-at100 filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=use&mask=userSpace-atZero filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=innerSVG&mask=userSpace-atZero filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=foreignObject&mask=userSpace-at100 filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=rect&filter=matrix-fillPaint-boundingBox filter-userspace-offset.svg +== filter-userspace-offset.svg?offsetContainer=rect&filter=matrix-fillPaint-userSpace-at100 filter-userspace-offset.svg From 51c046a07a8fa8ccd644ce92155697b85dc9fe3f Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Wed, 23 Apr 2014 11:47:31 +0200 Subject: [PATCH 10/40] Bug 997735 - Rename nsSVGIntegrationUtils::GetOffsetToUserSpace to GetOffsetToBoundingBox. r=roc There are three spaces that nsSVGIntegrationUtils needs to convert between. I'll call them "frame space", "bounding box frame space" and "user space". "Bounding box frame space" has its origin at the top left of the union of a frame's border boxes over all continuations. For SVG frames, "frame space" and "bounding box frame space" are the same because SVG frames don't have multiple continuations. For non-SVG frames, "bounding box frame space" and "user space" are the same. However, for SVG frames, "bounding box frame space" and "user space" are different! For example, for a , the point 0,0 in frame space is at the rect's top left corner, but the point 0,0 in user space is 100,100 pixels away from the rect's corner. nsSVGIntegrationUtils::GetOffsetToUserSpace took the non-SVG viewpoint, but it's misleading for SVG frames. --- layout/svg/nsSVGIntegrationUtils.cpp | 37 +++++++++++++++------------- layout/svg/nsSVGIntegrationUtils.h | 27 -------------------- 2 files changed, 20 insertions(+), 44 deletions(-) diff --git a/layout/svg/nsSVGIntegrationUtils.cpp b/layout/svg/nsSVGIntegrationUtils.cpp index 05af41ac7473..a37d1e720e19 100644 --- a/layout/svg/nsSVGIntegrationUtils.cpp +++ b/layout/svg/nsSVGIntegrationUtils.cpp @@ -154,8 +154,10 @@ nsSVGIntegrationUtils::UsingEffectsForFrame(const nsIFrame* aFrame) return (style->HasFilters() || style->mClipPath || style->mMask); } -/* static */ nsPoint -nsSVGIntegrationUtils::GetOffsetToUserSpace(nsIFrame* aFrame) +// For non-SVG frames, this gives the offset to the frame's "user space". +// For SVG frames, this returns a zero offset. +static nsPoint +GetOffsetToBoundingBox(nsIFrame* aFrame) { if ((aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) { // Do NOT call GetAllInFlowRectsUnion for SVG - it will get the @@ -208,7 +210,7 @@ nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(nsIFrame* aNonSVGFrame) nsLayoutUtils::FirstContinuationOrIBSplitSibling(aNonSVGFrame); // 'r' is in "user space": nsRect r = GetPreEffectsVisualOverflowUnion(firstFrame, nullptr, nsRect(), - GetOffsetToUserSpace(firstFrame)); + GetOffsetToBoundingBox(firstFrame)); return nsLayoutUtils::RectToGfxRect(r, aNonSVGFrame->PresContext()->AppUnitsPerCSSPixel()); } @@ -217,7 +219,7 @@ nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(nsIFrame* aNonSVGFrame) // continuations. When we're called for a frame with continuations, we're // called for each continuation in turn as it's reflowed. However, it isn't // until the last continuation is reflowed that this method's -// GetOffsetToUserSpace() and GetPreEffectsVisualOverflowUnion() calls will +// GetOffsetToBoundingBox() and GetPreEffectsVisualOverflowUnion() calls will // obtain valid border boxes for all the continuations. As a result, we'll // end up returning bogus post-filter visual overflow rects for all the prior // continuations. Unfortunately, by the time the last continuation is @@ -262,7 +264,7 @@ nsRect } // Create an override bbox - see comment above: - nsPoint firstFrameToUserSpace = GetOffsetToUserSpace(firstFrame); + nsPoint firstFrameToBoundingBox = GetOffsetToBoundingBox(firstFrame); // overrideBBox is in "user space", in _CSS_ pixels: // XXX Why are we rounding out to pixel boundaries? We don't do that in // GetSVGBBoxForNonSVGFrame, and it doesn't appear to be necessary. @@ -270,7 +272,7 @@ nsRect nsLayoutUtils::RectToGfxRect( GetPreEffectsVisualOverflowUnion(firstFrame, aFrame, aPreEffectsOverflowRect, - firstFrameToUserSpace), + firstFrameToBoundingBox), aFrame->PresContext()->AppUnitsPerCSSPixel()); overrideBBox.RoundOut(); @@ -278,7 +280,7 @@ nsRect nsFilterInstance::GetPostFilterBounds(firstFrame, &overrideBBox); // Return overflowRect relative to aFrame, rather than "user space": - return overflowRect - (aFrame->GetOffsetTo(firstFrame) + firstFrameToUserSpace); + return overflowRect - (aFrame->GetOffsetTo(firstFrame) + firstFrameToBoundingBox); } nsIntRect @@ -310,18 +312,18 @@ nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(nsIFrame* aFrame, return overflow.ToOutsidePixels(appUnitsPerDevPixel); } - // Convert aInvalidRect into "user space" in app units: - nsPoint toUserSpace = - aFrame->GetOffsetTo(firstFrame) + GetOffsetToUserSpace(firstFrame); + // Convert aInvalidRect into bounding box frame space in app units: + nsPoint toBoundingBox = + aFrame->GetOffsetTo(firstFrame) + GetOffsetToBoundingBox(firstFrame); // The initial rect was relative to the reference frame, so we need to // remove that offset to get a rect relative to the current frame. - toUserSpace -= aToReferenceFrame; - nsRect preEffectsRect = aInvalidRect.ToAppUnits(appUnitsPerDevPixel) + toUserSpace; + toBoundingBox -= aToReferenceFrame; + nsRect preEffectsRect = aInvalidRect.ToAppUnits(appUnitsPerDevPixel) + toBoundingBox; // Adjust the dirty area for effects, and shift it back to being relative to // the reference frame. nsRect result = nsFilterInstance::GetPostFilterDirtyArea(firstFrame, - preEffectsRect) - toUserSpace; + preEffectsRect) - toBoundingBox; // Return the result, in pixels relative to the reference frame. return result.ToOutsidePixels(appUnitsPerDevPixel); } @@ -341,7 +343,7 @@ nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(nsIFrame* aFrame, // Convert aDirtyRect into "user space" in app units: nsPoint toUserSpace = - aFrame->GetOffsetTo(firstFrame) + GetOffsetToUserSpace(firstFrame); + aFrame->GetOffsetTo(firstFrame) + GetOffsetToBoundingBox(firstFrame); nsRect postEffectsRect = aDirtyRect + toUserSpace; // Return ther result, relative to aFrame, not in user space: @@ -357,10 +359,11 @@ nsSVGIntegrationUtils::HitTestFrameForEffects(nsIFrame* aFrame, const nsPoint& a // Convert aPt to user space: nsPoint toUserSpace; if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) { + // XXXmstange Isn't this wrong for svg:use and innerSVG frames? toUserSpace = aFrame->GetPosition(); } else { toUserSpace = - aFrame->GetOffsetTo(firstFrame) + GetOffsetToUserSpace(firstFrame); + aFrame->GetOffsetTo(firstFrame) + GetOffsetToBoundingBox(firstFrame); } nsPoint pt = aPt + toUserSpace; return nsSVGUtils::HitTestClip(firstFrame, pt); @@ -460,7 +463,7 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx, gfxContext* gfx = aCtx->ThebesContext(); gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(gfx); - nsPoint firstFrameOffset = GetOffsetToUserSpace(firstFrame); + nsPoint firstFrameOffset = GetOffsetToBoundingBox(firstFrame); nsPoint offset = aBuilder->ToReferenceFrame(firstFrame) - firstFrameOffset; nsPoint offsetWithoutSVGGeomFramePos; if (firstFrame->IsFrameOfType(nsIFrame::eSVG)) { @@ -620,7 +623,7 @@ PaintFrameCallback::operator()(gfxContext* aContext, // to have it anchored at the top left corner of the bounding box of all of // mFrame's continuations. So we add a translation transform. int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel(); - nsPoint offset = nsSVGIntegrationUtils::GetOffsetToUserSpace(mFrame); + nsPoint offset = GetOffsetToBoundingBox(mFrame); gfxPoint devPxOffset = gfxPoint(offset.x, offset.y) / appUnitsPerDevPixel; aContext->Multiply(gfxMatrix().Translate(devPxOffset)); diff --git a/layout/svg/nsSVGIntegrationUtils.h b/layout/svg/nsSVGIntegrationUtils.h index 26433420463d..033c006306c2 100644 --- a/layout/svg/nsSVGIntegrationUtils.h +++ b/layout/svg/nsSVGIntegrationUtils.h @@ -42,33 +42,6 @@ public: static bool UsingEffectsForFrame(const nsIFrame* aFrame); - /** - * In SVG, an element's "user space" is simply the coordinate system in place - * at the time that it is drawn. For non-SVG frames, we want any SVG effects - * to be applied to the union of the border-box rects of all of a given - * frame's continuations. This means that, when we paint a non-SVG frame with - * effects, we want to offset the effects by the distance from the frame's - * origin (the top left of its border box) to the top left of the union of - * the border-box rects of all its continuations. In other words, we need to - * apply this offset as a suplimental translation to the current coordinate - * system in order to establish the correct user space before calling into - * the SVG effects code. For the purposes of the nsSVGIntegrationUtils code - * we somewhat misappropriate the term "user space" by using it to refer - * specifically to this adjusted coordinate system. - * - * For consistency with nsIFrame::GetOffsetTo, the offset this method returns - * is the offset you need to add to a point that's relative to aFrame's - * origin (the top left of its border box) to convert it to aFrame's user - * space. In other words the value returned is actually the offset from the - * origin of aFrame's user space to aFrame. - * - * Note: This method currently only accepts a frame's first continuation - * since none of our current callers need to be able to pass in other - * continuations. - */ - static nsPoint - GetOffsetToUserSpace(nsIFrame* aFrame); - /** * Returns the size of the union of the border-box rects of all of * aNonSVGFrame's continuations. From fc56b170d0f8c128d34a7a42b3e3a43ffdf243d7 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Wed, 23 Apr 2014 11:47:42 +0200 Subject: [PATCH 11/40] Bug 997735 - Add nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset. r=roc This function calculates the offset between "bounding box frame space" and "user space" for SVG frames. For non-SVG frames it returns no offset. It's crucial that this is consistent with what nsSVGUtils::GetBBox does. nsFilterInstance has several methods that are called by consumers before the actual painting, e.g. to calculate post filter extents or invalidation regions. Those nsFilterInstance APIs have their input and output values in "bounding box frame space" coordinates, but if the filter units are "objectBoundingBox", then those methods also do calculations involving the result of nsSVGUtils::GetBBox. So a consistent conversion is very important. --- layout/svg/nsSVGUtils.cpp | 31 +++++++++++++++++++++++++++++++ layout/svg/nsSVGUtils.h | 10 ++++++++++ 2 files changed, 41 insertions(+) diff --git a/layout/svg/nsSVGUtils.cpp b/layout/svg/nsSVGUtils.cpp index 16b25b7366c8..4e160e1c7570 100644 --- a/layout/svg/nsSVGUtils.cpp +++ b/layout/svg/nsSVGUtils.cpp @@ -889,6 +889,8 @@ nsSVGUtils::GetBBox(nsIFrame *aFrame, uint32_t aFlags) // The spec says getBBox "Returns the tight bounding box in *current user // space*". So we should really be doing this for all elements, but that // needs investigation to check that we won't break too much content. + // NOTE: When changing this to apply to other frame types, make sure to + // also update nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset. NS_ABORT_IF_FALSE(content->IsSVG(), "bad cast"); nsSVGElement *element = static_cast(content); matrix = element->PrependLocalTransformsTo(matrix, @@ -899,6 +901,35 @@ nsSVGUtils::GetBBox(nsIFrame *aFrame, uint32_t aFlags) return nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(aFrame); } +gfxPoint +nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(nsIFrame *aFrame) +{ + if (!(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) { + // The user space for non-SVG frames is defined as the bounding box of the + // frame's border-box rects over all continuations. + return gfxPoint(); + } + + // Leaf frames apply their own offset inside their user space. + if (aFrame->IsFrameOfType(nsIFrame::eSVGGeometry) || + aFrame->IsSVGText()) { + return nsLayoutUtils::RectToGfxRect(aFrame->GetRect(), + nsPresContext::AppUnitsPerCSSPixel()).TopLeft(); + } + + // For foreignObject frames, nsSVGUtils::GetBBox applies their local + // transform, so we need to do the same here. + if (aFrame->GetType() == nsGkAtoms::svgForeignObjectFrame) { + gfxMatrix transform = static_cast(aFrame->GetContent())-> + PrependLocalTransformsTo(gfxMatrix(), + nsSVGElement::eChildToUserSpace); + NS_ASSERTION(!transform.HasNonTranslation(), "we're relying on this being an offset-only transform"); + return transform.GetTranslation(); + } + + return gfxPoint(); +} + gfxRect nsSVGUtils::GetRelativeRect(uint16_t aUnits, const nsSVGLength2 *aXYWH, const gfxRect &aBBox, nsIFrame *aFrame) diff --git a/layout/svg/nsSVGUtils.h b/layout/svg/nsSVGUtils.h index 53037efd665b..5f99fa77f62f 100644 --- a/layout/svg/nsSVGUtils.h +++ b/layout/svg/nsSVGUtils.h @@ -405,6 +405,16 @@ public: static gfxRect GetBBox(nsIFrame *aFrame, uint32_t aFlags = eBBoxIncludeFillGeometry); + /* + * "User space" is the space that the frame's BBox (as calculated by + * nsSVGUtils::GetBBox) is in. "Frame space" is the space that has its origin + * at the top left of the union of the frame's border-box rects over all + * continuations. + * This function returns the offset one needs to add to something in frame + * space in order to get its coordinates in user space. + */ + static gfxPoint FrameSpaceInCSSPxToUserSpaceOffset(nsIFrame *aFrame); + /** * Convert a userSpaceOnUse/objectBoundingBoxUnits rectangle that's specified * using four nsSVGLength2 values into a user unit rectangle in user space. From bfe0e2ebe30efc4f77d499311c2c4115e322e8b8 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Wed, 23 Apr 2014 11:47:54 +0200 Subject: [PATCH 12/40] Bug 997735 - Use consistent offset both in nsSVGIntegrationUtils::PaintFramesWithEffects and in nsFilterInstance::GetUserSpaceToFrameSpaceInCSSPxTransform. r=roc --- layout/svg/nsFilterInstance.cpp | 27 +-------------- layout/svg/nsSVGIntegrationUtils.cpp | 51 ++++++++++++++++------------ 2 files changed, 31 insertions(+), 47 deletions(-) diff --git a/layout/svg/nsFilterInstance.cpp b/layout/svg/nsFilterInstance.cpp index 4a99eca59c45..a0186e1c0aca 100644 --- a/layout/svg/nsFilterInstance.cpp +++ b/layout/svg/nsFilterInstance.cpp @@ -589,30 +589,5 @@ nsFilterInstance::FilterSpaceToFrameSpace(const nsIntRect& aRect) const gfxMatrix nsFilterInstance::GetUserSpaceToFrameSpaceInCSSPxTransform() const { - gfxMatrix userToFrameSpaceInCSSPx; - - if ((mTargetFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) { - // As currently implemented by Mozilla for the purposes of filters, user - // space is the coordinate system established by GetCanvasTM(), since - // that's what we use to set filterToDeviceSpace above. In other words, - // for SVG, user space is actually the coordinate system aTarget - // establishes for _its_ children (i.e. after taking account of any x/y - // and viewBox attributes), not the coordinate system that is established - // for it by its 'transform' attribute (or by its _parent_) as it's - // normally defined. (XXX We should think about fixing this.) The only - // frame type for which these extra transforms are not simply an x/y - // translation is nsSVGInnerSVGFrame, hence we treat it specially here. - if (mTargetFrame->GetType() == nsGkAtoms::svgInnerSVGFrame) { - userToFrameSpaceInCSSPx = - static_cast(mTargetFrame->GetContent())-> - PrependLocalTransformsTo(gfxMatrix()); - } else { - gfxPoint targetsUserSpaceOffset = - nsLayoutUtils::RectToGfxRect(mTargetFrame->GetRect(), - mAppUnitsPerCSSPx).TopLeft(); - userToFrameSpaceInCSSPx.Translate(-targetsUserSpaceOffset); - } - } - // else, for all other frames, leave as the identity matrix - return userToFrameSpaceInCSSPx; + return gfxMatrix().Translate(-nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(mTargetFrame)); } diff --git a/layout/svg/nsSVGIntegrationUtils.cpp b/layout/svg/nsSVGIntegrationUtils.cpp index a37d1e720e19..f71fe5ca05d3 100644 --- a/layout/svg/nsSVGIntegrationUtils.cpp +++ b/layout/svg/nsSVGIntegrationUtils.cpp @@ -464,27 +464,35 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx, gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(gfx); nsPoint firstFrameOffset = GetOffsetToBoundingBox(firstFrame); - nsPoint offset = aBuilder->ToReferenceFrame(firstFrame) - firstFrameOffset; - nsPoint offsetWithoutSVGGeomFramePos; - if (firstFrame->IsFrameOfType(nsIFrame::eSVG)) { - offsetWithoutSVGGeomFramePos = offset; - } else { + nsPoint offsetToBoundingBox = aBuilder->ToReferenceFrame(firstFrame) - firstFrameOffset; + if (!firstFrame->IsFrameOfType(nsIFrame::eSVG)) { /* Snap the offset if the reference frame is not a SVG frame, * since other frames will be snapped to pixel when rendering. */ - offsetWithoutSVGGeomFramePos = nsPoint( - aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(offset.x), - aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(offset.y)); - } - nsPoint svgGeomFramePos; - if (aFrame->IsFrameOfType(nsIFrame::eSVGGeometry) || - aFrame->IsSVGText()) { - // SVG leaf frames apply their offset themselves, we need to unapply it at - // various points below to prevent it being double counted. - svgGeomFramePos = aFrame->GetPosition(); - offsetWithoutSVGGeomFramePos -= svgGeomFramePos; + offsetToBoundingBox = nsPoint( + aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.x), + aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.y)); } - aCtx->Translate(offsetWithoutSVGGeomFramePos); + // After applying only "offsetToBoundingBox", aCtx would have its origin at + // the top left corner of aFrame's bounding box (over all continuations). + // However, SVG painting needs the origin to be located at the origin of the + // SVG frame's "user space", i.e. the space in which, for example, the + // frame's BBox lives. + // SVG geometry frames and foreignObject frames apply their own offsets, so + // their position is relative to their user space. So for these frame types, + // if we want aCtx to be in user space, we first need to subtract the + // frame's position so that SVG painting can later add it again and the + // frame is painted in the right place. + + gfxPoint toUserSpaceGfx = nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(aFrame); + nsPoint toUserSpace(nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.x)), + nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.y))); + nsPoint offsetToUserSpace = offsetToBoundingBox - toUserSpace; + + NS_ASSERTION(hasSVGLayout || offsetToBoundingBox == offsetToUserSpace, + "For non-SVG frames there shouldn't be any additional offset"); + + aCtx->Translate(offsetToUserSpace); gfxMatrix cssPxToDevPxMatrix = GetCSSPxToDevPxMatrix(aFrame); @@ -496,7 +504,7 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx, complexEffects = true; gfx->Save(); aCtx->IntersectClip(aFrame->GetVisualOverflowRectRelativeToSelf() + - svgGeomFramePos); + toUserSpace); gfx->PushGroup(gfxContentType::COLOR_ALPHA); } @@ -511,13 +519,14 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx, /* Paint the child */ if (effectProperties.HasValidFilter()) { RegularFramePaintCallback callback(aBuilder, aLayerManager, - offsetWithoutSVGGeomFramePos); - nsRect dirtyRect = aDirtyRect - offset; + offsetToUserSpace); + + nsRect dirtyRect = aDirtyRect - offsetToBoundingBox; nsFilterInstance::PaintFilteredFrame(aCtx, aFrame, &callback, &dirtyRect); } else { gfx->SetMatrix(matrixAutoSaveRestore.Matrix()); aLayerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer, aBuilder); - aCtx->Translate(offsetWithoutSVGGeomFramePos); + aCtx->Translate(offsetToUserSpace); } if (clipPathFrame && isTrivialClip) { From 3db3aca9c1a404c2eee787d4d883fd11261cd935 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Wed, 23 Apr 2014 11:48:07 +0200 Subject: [PATCH 13/40] Bug 997735 - Invalidate when reflowing SVG containers. r=roc Without this patch, when changing the x/y attributes of svg:use, innerSVG and foreignObject, we were relying on the transform changes of the children to trigger the right invalidations. However, changes to those attributes can also change the filter region. And there's a difference between moving children in a fixed filter region and moving the filter region along with the children: In the first case, we wouldn't need to invalidate anything outside the old filter region, because those parts of the children would be clipped away anyway. But when the filter region changes, we need to invalidate both the old and the new filter region. Also, when the filter has primitives without inputs, e.g. flood or turbulence, the filtered frame needs to be invalidate even if it has no children. --- layout/svg/nsSVGForeignObjectFrame.cpp | 6 ++++++ layout/svg/nsSVGInnerSVGFrame.cpp | 7 +++++++ layout/svg/nsSVGUseFrame.cpp | 7 +++++++ 3 files changed, 20 insertions(+) diff --git a/layout/svg/nsSVGForeignObjectFrame.cpp b/layout/svg/nsSVGForeignObjectFrame.cpp index 44872728b990..c562b05204ed 100644 --- a/layout/svg/nsSVGForeignObjectFrame.cpp +++ b/layout/svg/nsSVGForeignObjectFrame.cpp @@ -382,6 +382,12 @@ nsSVGForeignObjectFrame::ReflowSVG() nsSVGEffects::UpdateEffects(this); } + // If we have a filter, we need to invalidate ourselves because filter + // output can change even if none of our descendants need repainting. + if (StyleSVGReset()->HasFilters()) { + InvalidateFrame(); + } + // TODO: once we support |overflow:visible| on foreignObject, then we will // need to take account of our descendants here. nsRect overflow = nsRect(nsPoint(0,0), mRect.Size()); diff --git a/layout/svg/nsSVGInnerSVGFrame.cpp b/layout/svg/nsSVGInnerSVGFrame.cpp index c377679256a6..0ac21d3116f2 100644 --- a/layout/svg/nsSVGInnerSVGFrame.cpp +++ b/layout/svg/nsSVGInnerSVGFrame.cpp @@ -102,6 +102,13 @@ nsSVGInnerSVGFrame::ReflowSVG() mRect = nsLayoutUtils::RoundGfxRectToAppRect( gfxRect(x, y, width, height), PresContext()->AppUnitsPerCSSPixel()); + + // If we have a filter, we need to invalidate ourselves because filter + // output can change even if none of our descendants need repainting. + if (StyleSVGReset()->HasFilters()) { + InvalidateFrame(); + } + nsSVGInnerSVGFrameBase::ReflowSVG(); } diff --git a/layout/svg/nsSVGUseFrame.cpp b/layout/svg/nsSVGUseFrame.cpp index c9a22107c2b3..7c628513edaf 100644 --- a/layout/svg/nsSVGUseFrame.cpp +++ b/layout/svg/nsSVGUseFrame.cpp @@ -187,6 +187,13 @@ nsSVGUseFrame::ReflowSVG() mRect.MoveTo(nsLayoutUtils::RoundGfxRectToAppRect( gfxRect(x, y, 0.0, 0.0), PresContext()->AppUnitsPerCSSPixel()).TopLeft()); + + // If we have a filter, we need to invalidate ourselves because filter + // output can change even if none of our descendants need repainting. + if (StyleSVGReset()->HasFilters()) { + InvalidateFrame(); + } + nsSVGUseFrameBase::ReflowSVG(); } From f5b5ee3aa703199f81a13ff645dba15a8e352a62 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Wed, 23 Apr 2014 11:56:21 +0200 Subject: [PATCH 14/40] Bug 999559 part 1 - Rename IonFrameIterator to JitFrameIterator. r=shu --HG-- rename : js/src/jit/IonFrameIterator-inl.h => js/src/jit/JitFrameIterator-inl.h rename : js/src/jit/IonFrameIterator.h => js/src/jit/JitFrameIterator.h --- js/src/jit/Bailouts.cpp | 14 +-- js/src/jit/Bailouts.h | 10 +- js/src/jit/BaselineBailouts.cpp | 2 +- js/src/jit/BaselineFrame.cpp | 4 +- js/src/jit/BaselineFrame.h | 2 +- js/src/jit/BaselineIC.cpp | 2 +- js/src/jit/BaselineJIT.cpp | 2 +- js/src/jit/Ion.cpp | 4 +- js/src/jit/IonFrames-inl.h | 16 +-- js/src/jit/IonFrames.cpp | 100 +++++++++--------- js/src/jit/IonFrames.h | 4 +- ...eIterator-inl.h => JitFrameIterator-inl.h} | 10 +- ...{IonFrameIterator.h => JitFrameIterator.h} | 30 +++--- js/src/jit/VMFunctions.cpp | 2 +- js/src/jit/arm/Bailouts-arm.cpp | 4 +- js/src/jit/x64/Bailouts-x64.cpp | 4 +- js/src/jit/x86/Bailouts-x86.cpp | 4 +- js/src/jsfun.cpp | 2 +- js/src/vm/Stack.cpp | 10 +- js/src/vm/Stack.h | 4 +- 20 files changed, 115 insertions(+), 115 deletions(-) rename js/src/jit/{IonFrameIterator-inl.h => JitFrameIterator-inl.h} (84%) rename js/src/jit/{IonFrameIterator.h => JitFrameIterator.h} (96%) diff --git a/js/src/jit/Bailouts.cpp b/js/src/jit/Bailouts.cpp index 6491e566b586..65aa8d252cdc 100644 --- a/js/src/jit/Bailouts.cpp +++ b/js/src/jit/Bailouts.cpp @@ -15,7 +15,7 @@ #include "jit/Snapshots.h" #include "vm/TraceLogging.h" -#include "jit/IonFrameIterator-inl.h" +#include "jit/JitFrameIterator-inl.h" #include "vm/Stack-inl.h" using namespace js; @@ -24,15 +24,15 @@ using namespace js::jit; // These constructor are exactly the same except for the type of the iterator // which is given to the SnapshotIterator constructor. Doing so avoid the // creation of virtual functions for the IonIterator but may introduce some -// weirdness as IonInlineIterator is using an IonFrameIterator reference. +// weirdness as IonInlineIterator is using a JitFrameIterator reference. // // If a function relies on ionScript() or to use OsiIndex(), due to the -// lack of virtual, these functions will use the IonFrameIterator reference +// lack of virtual, these functions will use the JitFrameIterator reference // contained in the InlineFrameIterator and thus are not able to recover // correctly the data stored in IonBailoutIterator. // // Currently, such cases should not happen because our only use case of the -// IonFrameIterator within InlineFrameIterator is to read the frame content, or +// JitFrameIterator within InlineFrameIterator is to read the frame content, or // to clone it to find the parent scripted frame. Both use cases are fine and // should not cause any issue since the only potential issue is to read the // bailed out frame. @@ -63,7 +63,7 @@ IonBailoutIterator::dump() const ++frames; } } else { - IonFrameIterator::dump(); + JitFrameIterator::dump(); } } @@ -151,8 +151,8 @@ jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut, } IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, - const IonFrameIterator &frame) - : IonFrameIterator(activations), + const JitFrameIterator &frame) + : JitFrameIterator(activations), machine_(frame.machineState()) { returnAddressToFp_ = frame.returnAddressToFp(); diff --git a/js/src/jit/Bailouts.h b/js/src/jit/Bailouts.h index 50e2e817d54a..c3a542b6b27c 100644 --- a/js/src/jit/Bailouts.h +++ b/js/src/jit/Bailouts.h @@ -9,8 +9,8 @@ #include "jstypes.h" -#include "jit/IonFrameIterator.h" #include "jit/IonFrames.h" +#include "jit/JitFrameIterator.h" #include "vm/Stack.h" namespace js { @@ -111,8 +111,8 @@ class InvalidationBailoutStack; // This iterator is constructed at a time where there is no exit frame at the // moment. They must be initialized to the first JS frame instead of the exit -// frame as usually done with IonFrameIterator. -class IonBailoutIterator : public IonFrameIterator +// frame as usually done with JitFrameIterator. +class IonBailoutIterator : public JitFrameIterator { MachineState machine_; uint32_t snapshotOffset_; @@ -122,7 +122,7 @@ class IonBailoutIterator : public IonFrameIterator public: IonBailoutIterator(const JitActivationIterator &activations, BailoutStack *sp); IonBailoutIterator(const JitActivationIterator &activations, InvalidationBailoutStack *sp); - IonBailoutIterator(const JitActivationIterator &activations, const IonFrameIterator &frame); + IonBailoutIterator(const JitActivationIterator &activations, const JitFrameIterator &frame); SnapshotOffset snapshotOffset() const { JS_ASSERT(topIonScript_); @@ -138,7 +138,7 @@ class IonBailoutIterator : public IonFrameIterator IonScript *ionScript() const { if (topIonScript_) return topIonScript_; - return IonFrameIterator::ionScript(); + return JitFrameIterator::ionScript(); } void dump() const; diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index 9bffcb9d968d..8a16f4ba8cca 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -1538,7 +1538,7 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo) RootedScript outerScript(cx, nullptr); JS_ASSERT(cx->currentlyRunningInJit()); - IonFrameIterator iter(cx); + JitFrameIterator iter(cx); uint32_t frameno = 0; while (frameno < numFrames) { diff --git a/js/src/jit/BaselineFrame.cpp b/js/src/jit/BaselineFrame.cpp index 97f71d5066c3..b0fd64d7fa75 100644 --- a/js/src/jit/BaselineFrame.cpp +++ b/js/src/jit/BaselineFrame.cpp @@ -28,7 +28,7 @@ MarkLocals(BaselineFrame *frame, JSTracer *trc, unsigned start, unsigned end) } void -BaselineFrame::trace(JSTracer *trc, IonFrameIterator &frameIterator) +BaselineFrame::trace(JSTracer *trc, JitFrameIterator &frameIterator) { replaceCalleeToken(MarkCalleeToken(trc, calleeToken())); @@ -208,7 +208,7 @@ BaselineFrame::initForOsr(InterpreterFrame *fp, uint32_t numStackValues) // debugger, wants a valid return address, but it's okay to just pick one. // In debug mode there's always at least 1 ICEntry (since there are always // debug prologue/epilogue calls). - IonFrameIterator iter(cx); + JitFrameIterator iter(cx); JS_ASSERT(iter.returnAddress() == nullptr); BaselineScript *baseline = fp->script()->baselineScript(); iter.current()->setReturnAddress(baseline->returnAddressForIC(baseline->icEntry(0))); diff --git a/js/src/jit/BaselineFrame.h b/js/src/jit/BaselineFrame.h index eede6a19eec7..f617c7014dea 100644 --- a/js/src/jit/BaselineFrame.h +++ b/js/src/jit/BaselineFrame.h @@ -296,7 +296,7 @@ class BaselineFrame flags_ |= OVER_RECURSED; } - void trace(JSTracer *trc, IonFrameIterator &frame); + void trace(JSTracer *trc, JitFrameIterator &frame); bool isFunctionFrame() const { return CalleeTokenIsFunction(calleeToken()); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index ac4769262606..2d550700ad21 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -773,7 +773,7 @@ IsTopFrameConstructing(JSContext *cx) { JS_ASSERT(cx->currentlyRunningInJit()); JitActivationIterator activations(cx->runtime()); - IonFrameIterator iter(activations); + JitFrameIterator iter(activations); JS_ASSERT(iter.type() == JitFrame_Exit); ++iter; diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index 6604a2ffafb5..bbc9021e14d1 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -931,7 +931,7 @@ jit::ToggleBaselineSPS(JSRuntime *runtime, bool enable) static void MarkActiveBaselineScripts(JSRuntime *rt, const JitActivationIterator &activation) { - for (jit::IonFrameIterator iter(activation); !iter.done(); ++iter) { + for (jit::JitFrameIterator iter(activation); !iter.done(); ++iter) { switch (iter.type()) { case JitFrame_BaselineJS: iter.script()->baselineScript()->setActive(); diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index df020c94695d..895275247580 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -2514,7 +2514,7 @@ InvalidateActivation(FreeOp *fop, uint8_t *ionTop, bool invalidateAll) size_t frameno = 1; - for (IonFrameIterator it(ionTop, SequentialExecution); !it.done(); ++it, ++frameno) { + for (JitFrameIterator it(ionTop, SequentialExecution); !it.done(); ++it, ++frameno) { JS_ASSERT_IF(frameno == 1, it.type() == JitFrame_Exit); #ifdef DEBUG @@ -2880,7 +2880,7 @@ jit::ForbidCompilation(JSContext *cx, JSScript *script, ExecutionMode mode) case SequentialExecution: if (script->hasIonScript()) { // It is only safe to modify script->ion if the script is not currently - // running, because IonFrameIterator needs to tell what ionScript to + // running, because JitFrameIterator needs to tell what ionScript to // use (either the one on the JSScript, or the one hidden in the // breadcrumbs Invalidation() leaves). Therefore, if invalidation // fails, we cannot disable the script. diff --git a/js/src/jit/IonFrames-inl.h b/js/src/jit/IonFrames-inl.h index 8e10b4fde839..31dfe2d67e65 100644 --- a/js/src/jit/IonFrames-inl.h +++ b/js/src/jit/IonFrames-inl.h @@ -11,11 +11,11 @@ #include "jit/IonFrames.h" -#include "jit/IonFrameIterator.h" +#include "jit/JitFrameIterator.h" #include "jit/LIR.h" #include "vm/ForkJoin.h" -#include "jit/IonFrameIterator-inl.h" +#include "jit/JitFrameIterator-inl.h" namespace js { namespace jit { @@ -31,28 +31,28 @@ SafepointIndex::resolve() } inline uint8_t * -IonFrameIterator::returnAddress() const +JitFrameIterator::returnAddress() const { IonCommonFrameLayout *current = (IonCommonFrameLayout *) current_; return current->returnAddress(); } inline size_t -IonFrameIterator::prevFrameLocalSize() const +JitFrameIterator::prevFrameLocalSize() const { IonCommonFrameLayout *current = (IonCommonFrameLayout *) current_; return current->prevFrameLocalSize(); } inline FrameType -IonFrameIterator::prevType() const +JitFrameIterator::prevType() const { IonCommonFrameLayout *current = (IonCommonFrameLayout *) current_; return current->prevType(); } inline bool -IonFrameIterator::isFakeExitFrame() const +JitFrameIterator::isFakeExitFrame() const { bool res = (prevType() == JitFrame_Unwound_Rectifier || prevType() == JitFrame_Unwound_IonJS || @@ -62,7 +62,7 @@ IonFrameIterator::isFakeExitFrame() const } inline IonExitFrameLayout * -IonFrameIterator::exitFrame() const +JitFrameIterator::exitFrame() const { JS_ASSERT(type() == JitFrame_Exit); JS_ASSERT(!isFakeExitFrame()); @@ -72,7 +72,7 @@ IonFrameIterator::exitFrame() const inline BaselineFrame * GetTopBaselineFrame(JSContext *cx) { - IonFrameIterator iter(cx); + JitFrameIterator iter(cx); JS_ASSERT(iter.type() == JitFrame_Exit); ++iter; if (iter.isBaselineStub()) diff --git a/js/src/jit/IonFrames.cpp b/js/src/jit/IonFrames.cpp index 12bb0fbd64e3..02430c2d9aa2 100644 --- a/js/src/jit/IonFrames.cpp +++ b/js/src/jit/IonFrames.cpp @@ -27,7 +27,7 @@ #include "vm/ForkJoin.h" #include "vm/Interpreter.h" -#include "jit/IonFrameIterator-inl.h" +#include "jit/JitFrameIterator-inl.h" #include "vm/Probes-inl.h" namespace js { @@ -72,7 +72,7 @@ ReadFrameBooleanSlot(IonJSFrameLayout *fp, int32_t slot) return *(bool *)((char *)fp + OffsetOfFrameSlot(slot)); } -IonFrameIterator::IonFrameIterator(JSContext *cx) +JitFrameIterator::JitFrameIterator(JSContext *cx) : current_(cx->mainThread().ionTop), type_(JitFrame_Exit), returnAddressToFp_(nullptr), @@ -83,7 +83,7 @@ IonFrameIterator::IonFrameIterator(JSContext *cx) { } -IonFrameIterator::IonFrameIterator(const ActivationIterator &activations) +JitFrameIterator::JitFrameIterator(const ActivationIterator &activations) : current_(activations.jitTop()), type_(JitFrame_Exit), returnAddressToFp_(nullptr), @@ -94,7 +94,7 @@ IonFrameIterator::IonFrameIterator(const ActivationIterator &activations) { } -IonFrameIterator::IonFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode) +JitFrameIterator::JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode) : current_((uint8_t *)fp), type_(JitFrame_IonJS), returnAddressToFp_(fp->returnAddress()), @@ -104,14 +104,14 @@ IonFrameIterator::IonFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode) } bool -IonFrameIterator::checkInvalidation() const +JitFrameIterator::checkInvalidation() const { IonScript *dummy; return checkInvalidation(&dummy); } bool -IonFrameIterator::checkInvalidation(IonScript **ionScriptOut) const +JitFrameIterator::checkInvalidation(IonScript **ionScriptOut) const { uint8_t *returnAddr = returnAddressToFp(); JSScript *script = this->script(); @@ -137,13 +137,13 @@ IonFrameIterator::checkInvalidation(IonScript **ionScriptOut) const } CalleeToken -IonFrameIterator::calleeToken() const +JitFrameIterator::calleeToken() const { return ((IonJSFrameLayout *) current_)->calleeToken(); } JSFunction * -IonFrameIterator::callee() const +JitFrameIterator::callee() const { JS_ASSERT(isScripted()); JS_ASSERT(isFunctionFrame()); @@ -151,7 +151,7 @@ IonFrameIterator::callee() const } JSFunction * -IonFrameIterator::maybeCallee() const +JitFrameIterator::maybeCallee() const { if (isScripted() && (isFunctionFrame())) return callee(); @@ -159,7 +159,7 @@ IonFrameIterator::maybeCallee() const } bool -IonFrameIterator::isNative() const +JitFrameIterator::isNative() const { if (type_ != JitFrame_Exit || isFakeExitFrame()) return false; @@ -167,7 +167,7 @@ IonFrameIterator::isNative() const } bool -IonFrameIterator::isOOLNative() const +JitFrameIterator::isOOLNative() const { if (type_ != JitFrame_Exit) return false; @@ -175,7 +175,7 @@ IonFrameIterator::isOOLNative() const } bool -IonFrameIterator::isOOLPropertyOp() const +JitFrameIterator::isOOLPropertyOp() const { if (type_ != JitFrame_Exit) return false; @@ -183,7 +183,7 @@ IonFrameIterator::isOOLPropertyOp() const } bool -IonFrameIterator::isOOLProxy() const +JitFrameIterator::isOOLProxy() const { if (type_ != JitFrame_Exit) return false; @@ -191,7 +191,7 @@ IonFrameIterator::isOOLProxy() const } bool -IonFrameIterator::isDOMExit() const +JitFrameIterator::isDOMExit() const { if (type_ != JitFrame_Exit) return false; @@ -199,13 +199,13 @@ IonFrameIterator::isDOMExit() const } bool -IonFrameIterator::isFunctionFrame() const +JitFrameIterator::isFunctionFrame() const { return CalleeTokenIsFunction(calleeToken()); } JSScript * -IonFrameIterator::script() const +JitFrameIterator::script() const { JS_ASSERT(isScripted()); if (isBaselineJS()) @@ -216,7 +216,7 @@ IonFrameIterator::script() const } void -IonFrameIterator::baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes) const +JitFrameIterator::baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes) const { JS_ASSERT(isBaselineJS()); JSScript *script = this->script(); @@ -246,7 +246,7 @@ IonFrameIterator::baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes) } Value * -IonFrameIterator::actualArgs() const +JitFrameIterator::actualArgs() const { return jsFrame()->argv() + 1; } @@ -275,7 +275,7 @@ SizeOfFramePrefix(FrameType type) } uint8_t * -IonFrameIterator::prevFp() const +JitFrameIterator::prevFp() const { size_t currentSize = SizeOfFramePrefix(type_); // This quick fix must be removed as soon as bug 717297 land. This is @@ -290,8 +290,8 @@ IonFrameIterator::prevFp() const return current_ + currentSize; } -IonFrameIterator & -IonFrameIterator::operator++() +JitFrameIterator & +JitFrameIterator::operator++() { JS_ASSERT(type_ != JitFrame_Entry); @@ -319,7 +319,7 @@ IonFrameIterator::operator++() } uintptr_t * -IonFrameIterator::spillBase() const +JitFrameIterator::spillBase() const { // Get the base address to where safepoint registers are spilled. // Out-of-line calls do not unwind the extra padding space used to @@ -329,7 +329,7 @@ IonFrameIterator::spillBase() const } MachineState -IonFrameIterator::machineState() const +JitFrameIterator::machineState() const { SafepointReader reader(ionScript(), safepoint()); uintptr_t *spill = spillBase(); @@ -446,7 +446,7 @@ HandleExceptionIon(JSContext *cx, const InlineFrameIterator &frame, ResumeFromEx } static void -HandleExceptionBaseline(JSContext *cx, const IonFrameIterator &frame, ResumeFromException *rfe, +HandleExceptionBaseline(JSContext *cx, const JitFrameIterator &frame, ResumeFromException *rfe, bool *calledDebugEpilogue) { JS_ASSERT(frame.isBaselineJS()); @@ -583,7 +583,7 @@ HandleException(ResumeFromException *rfe) if (cx->runtime()->hasIonReturnOverride()) cx->runtime()->takeIonReturnOverride(); - IonFrameIterator iter(cx); + JitFrameIterator iter(cx); while (!iter.isEntry()) { bool overrecursed = false; if (iter.isIonJS()) { @@ -693,7 +693,7 @@ void HandleParallelFailure(ResumeFromException *rfe) { ForkJoinContext *cx = ForkJoinContext::current(); - IonFrameIterator iter(cx->perThreadData->ionTop, ParallelExecution); + JitFrameIterator iter(cx->perThreadData->ionTop, ParallelExecution); parallel::Spew(parallel::SpewBailouts, "Bailing from VM reentry"); @@ -774,7 +774,7 @@ MarkCalleeToken(JSTracer *trc, CalleeToken token) #ifdef JS_NUNBOX32 static inline uintptr_t -ReadAllocation(const IonFrameIterator &frame, const LAllocation *a) +ReadAllocation(const JitFrameIterator &frame, const LAllocation *a) { if (a->isGeneralReg()) { Register reg = a->toGeneralReg()->reg(); @@ -791,7 +791,7 @@ ReadAllocation(const IonFrameIterator &frame, const LAllocation *a) #endif static void -MarkActualArguments(JSTracer *trc, const IonFrameIterator &frame) +MarkActualArguments(JSTracer *trc, const JitFrameIterator &frame) { IonJSFrameLayout *layout = frame.jsFrame(); JS_ASSERT(CalleeTokenIsFunction(layout->calleeToken())); @@ -806,7 +806,7 @@ MarkActualArguments(JSTracer *trc, const IonFrameIterator &frame) #ifdef JS_NUNBOX32 static inline void -WriteAllocation(const IonFrameIterator &frame, const LAllocation *a, uintptr_t value) +WriteAllocation(const JitFrameIterator &frame, const LAllocation *a, uintptr_t value) { if (a->isGeneralReg()) { Register reg = a->toGeneralReg()->reg(); @@ -825,7 +825,7 @@ WriteAllocation(const IonFrameIterator &frame, const LAllocation *a, uintptr_t v #endif static void -MarkIonJSFrame(JSTracer *trc, const IonFrameIterator &frame) +MarkIonJSFrame(JSTracer *trc, const JitFrameIterator &frame) { IonJSFrameLayout *layout = (IonJSFrameLayout *)frame.fp(); @@ -895,7 +895,7 @@ MarkIonJSFrame(JSTracer *trc, const IonFrameIterator &frame) #ifdef JSGC_GENERATIONAL static void -UpdateIonJSFrameForMinorGC(JSTracer *trc, const IonFrameIterator &frame) +UpdateIonJSFrameForMinorGC(JSTracer *trc, const JitFrameIterator &frame) { // Minor GCs may move slots/elements allocated in the nursery. Update // any slots/elements pointers stored in this frame. @@ -941,7 +941,7 @@ UpdateIonJSFrameForMinorGC(JSTracer *trc, const IonFrameIterator &frame) #endif static void -MarkBaselineStubFrame(JSTracer *trc, const IonFrameIterator &frame) +MarkBaselineStubFrame(JSTracer *trc, const JitFrameIterator &frame) { // Mark the ICStub pointer stored in the stub frame. This is necessary // so that we don't destroy the stub code after unlinking the stub. @@ -958,7 +958,7 @@ MarkBaselineStubFrame(JSTracer *trc, const IonFrameIterator &frame) void JitActivationIterator::jitStackRange(uintptr_t *&min, uintptr_t *&end) { - IonFrameIterator frames(jitTop(), SequentialExecution); + JitFrameIterator frames(jitTop(), SequentialExecution); if (frames.isFakeExitFrame()) { min = reinterpret_cast(frames.fp()); @@ -994,7 +994,7 @@ JitActivationIterator::jitStackRange(uintptr_t *&min, uintptr_t *&end) } static void -MarkJitExitFrame(JSTracer *trc, const IonFrameIterator &frame) +MarkJitExitFrame(JSTracer *trc, const JitFrameIterator &frame) { // Ignore fake exit frames created by EnsureExitFrame. if (frame.isFakeExitFrame()) @@ -1134,7 +1134,7 @@ MarkJitExitFrame(JSTracer *trc, const IonFrameIterator &frame) } static void -MarkRectifierFrame(JSTracer *trc, const IonFrameIterator &frame) +MarkRectifierFrame(JSTracer *trc, const JitFrameIterator &frame) { // Mark thisv. // @@ -1157,7 +1157,7 @@ MarkJitActivation(JSTracer *trc, const JitActivationIterator &activations) } #endif - for (IonFrameIterator frames(activations); !frames.done(); ++frames) { + for (JitFrameIterator frames(activations); !frames.done(); ++frames) { switch (frames.type()) { case JitFrame_Exit: MarkJitExitFrame(trc, frames); @@ -1197,7 +1197,7 @@ UpdateJitActivationsForMinorGC(JSRuntime *rt, JSTracer *trc) { JS_ASSERT(trc->runtime()->isHeapMinorCollecting()); for (JitActivationIterator activations(rt); !activations.done(); ++activations) { - for (IonFrameIterator frames(activations); !frames.done(); ++frames) { + for (JitFrameIterator frames(activations); !frames.done(); ++frames) { if (frames.type() == JitFrame_IonJS) UpdateIonJSFrameForMinorGC(trc, frames); } @@ -1220,7 +1220,7 @@ GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes) JSRuntime *rt = cx->runtime(); // Recover the return address. - IonFrameIterator it(rt->mainThread.ionTop, SequentialExecution); + JitFrameIterator it(rt->mainThread.ionTop, SequentialExecution); // If the previous frame is a rectifier frame (maybe unwound), // skip past it. @@ -1306,7 +1306,7 @@ SnapshotIterator::SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshot JS_ASSERT(snapshotOffset < ionScript->snapshotsListSize()); } -SnapshotIterator::SnapshotIterator(const IonFrameIterator &iter) +SnapshotIterator::SnapshotIterator(const JitFrameIterator &iter) : snapshot_(iter.ionScript()->snapshots(), iter.osiIndex()->snapshotOffset(), iter.ionScript()->snapshotsRVATableSize(), @@ -1536,7 +1536,7 @@ SnapshotIterator::nextFrame() } IonScript * -IonFrameIterator::ionScript() const +JitFrameIterator::ionScript() const { JS_ASSERT(type() == JitFrame_IonJS); @@ -1553,7 +1553,7 @@ IonFrameIterator::ionScript() const } const SafepointIndex * -IonFrameIterator::safepoint() const +JitFrameIterator::safepoint() const { if (!cachedSafepointIndex_) cachedSafepointIndex_ = ionScript()->getSafepointIndex(returnAddressToFp()); @@ -1561,7 +1561,7 @@ IonFrameIterator::safepoint() const } const OsiIndex * -IonFrameIterator::osiIndex() const +JitFrameIterator::osiIndex() const { SafepointReader reader(ionScript(), safepoint()); return ionScript()->getOsiIndex(reader.osiReturnPointOffset()); @@ -1569,7 +1569,7 @@ IonFrameIterator::osiIndex() const template void -InlineFrameIteratorMaybeGC::resetOn(const IonFrameIterator *iter) +InlineFrameIteratorMaybeGC::resetOn(const JitFrameIterator *iter) { frame_ = iter; framesRead_ = 0; @@ -1580,8 +1580,8 @@ InlineFrameIteratorMaybeGC::resetOn(const IonFrameIterator *iter) findNextFrame(); } } -template void InlineFrameIteratorMaybeGC::resetOn(const IonFrameIterator *iter); -template void InlineFrameIteratorMaybeGC::resetOn(const IonFrameIterator *iter); +template void InlineFrameIteratorMaybeGC::resetOn(const JitFrameIterator *iter); +template void InlineFrameIteratorMaybeGC::resetOn(const JitFrameIterator *iter); template void @@ -1719,9 +1719,9 @@ template bool InlineFrameIteratorMaybeGC::isConstructing() const; template bool InlineFrameIteratorMaybeGC::isConstructing() const; bool -IonFrameIterator::isConstructing() const +JitFrameIterator::isConstructing() const { - IonFrameIterator parent(*this); + JitFrameIterator parent(*this); // Skip the current frame and look at the caller's. do { @@ -1760,7 +1760,7 @@ IonFrameIterator::isConstructing() const } unsigned -IonFrameIterator::numActualArgs() const +JitFrameIterator::numActualArgs() const { if (isScripted()) return jsFrame()->numActualArgs(); @@ -1791,7 +1791,7 @@ struct DumpOp { }; void -IonFrameIterator::dumpBaseline() const +JitFrameIterator::dumpBaseline() const { JS_ASSERT(isBaselineJS()); @@ -1898,7 +1898,7 @@ template void InlineFrameIteratorMaybeGC::dump() const; template void InlineFrameIteratorMaybeGC::dump() const; void -IonFrameIterator::dump() const +JitFrameIterator::dump() const { switch (type_) { case JitFrame_Entry: diff --git a/js/src/jit/IonFrames.h b/js/src/jit/IonFrames.h index 2488990d5b29..5316e529064a 100644 --- a/js/src/jit/IonFrames.h +++ b/js/src/jit/IonFrames.h @@ -14,7 +14,7 @@ #include "jscntxt.h" #include "jsfun.h" -#include "jit/IonFrameIterator.h" +#include "jit/JitFrameIterator.h" namespace js { namespace jit { @@ -282,7 +282,7 @@ MakeFrameDescriptor(uint32_t frameSize, FrameType type) inline JSScript * GetTopIonJSScript(uint8_t *ionTop, void **returnAddrOut, ExecutionMode mode) { - IonFrameIterator iter(ionTop, mode); + JitFrameIterator iter(ionTop, mode); JS_ASSERT(iter.type() == JitFrame_Exit); ++iter; diff --git a/js/src/jit/IonFrameIterator-inl.h b/js/src/jit/JitFrameIterator-inl.h similarity index 84% rename from js/src/jit/IonFrameIterator-inl.h rename to js/src/jit/JitFrameIterator-inl.h index dbf2c18b3bab..1211d0f4dd2d 100644 --- a/js/src/jit/IonFrameIterator-inl.h +++ b/js/src/jit/JitFrameIterator-inl.h @@ -4,12 +4,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef jit_IonFrameIterator_inl_h -#define jit_IonFrameIterator_inl_h +#ifndef jit_JitFrameIterator_inl_h +#define jit_JitFrameIterator_inl_h #ifdef JS_ION -#include "jit/IonFrameIterator.h" +#include "jit/JitFrameIterator.h" #include "jit/Bailouts.h" #include "jit/BaselineFrame.h" @@ -34,7 +34,7 @@ InlineFrameIteratorMaybeGC::InlineFrameIteratorMaybeGC( } inline BaselineFrame * -IonFrameIterator::baselineFrame() const +JitFrameIterator::baselineFrame() const { JS_ASSERT(isBaselineJS()); return (BaselineFrame *)(fp() - BaselineFrame::FramePointerOffset - BaselineFrame::Size()); @@ -45,4 +45,4 @@ IonFrameIterator::baselineFrame() const #endif // JS_ION -#endif /* jit_IonFrameIterator_inl_h */ +#endif /* jit_JitFrameIterator_inl_h */ diff --git a/js/src/jit/IonFrameIterator.h b/js/src/jit/JitFrameIterator.h similarity index 96% rename from js/src/jit/IonFrameIterator.h rename to js/src/jit/JitFrameIterator.h index cf1d4c16b067..2d3d7a15beaa 100644 --- a/js/src/jit/IonFrameIterator.h +++ b/js/src/jit/JitFrameIterator.h @@ -4,8 +4,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef jit_IonFrameIterator_h -#define jit_IonFrameIterator_h +#ifndef jit_JitFrameIterator_h +#define jit_JitFrameIterator_h #ifdef JS_ION @@ -81,7 +81,7 @@ class BaselineFrame; class JitActivation; -class IonFrameIterator +class JitFrameIterator { protected: uint8_t *current_; @@ -97,7 +97,7 @@ class IonFrameIterator void dumpBaseline() const; public: - explicit IonFrameIterator(uint8_t *top, ExecutionMode mode) + explicit JitFrameIterator(uint8_t *top, ExecutionMode mode) : current_(top), type_(JitFrame_Exit), returnAddressToFp_(nullptr), @@ -107,9 +107,9 @@ class IonFrameIterator mode_(mode) { } - explicit IonFrameIterator(JSContext *cx); - explicit IonFrameIterator(const ActivationIterator &activations); - explicit IonFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode); + explicit JitFrameIterator(JSContext *cx); + explicit JitFrameIterator(const ActivationIterator &activations); + explicit JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode); // Current frame information. FrameType type() const { @@ -195,7 +195,7 @@ class IonFrameIterator inline bool done() const { return type_ == JitFrame_Entry; } - IonFrameIterator &operator++(); + JitFrameIterator &operator++(); // Returns the IonScript associated with this JS frame. IonScript *ionScript() const; @@ -351,7 +351,7 @@ class SnapshotIterator SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset, IonJSFrameLayout *fp, const MachineState &machine); - SnapshotIterator(const IonFrameIterator &iter); + SnapshotIterator(const JitFrameIterator &iter); SnapshotIterator(const IonBailoutIterator &iter); SnapshotIterator(); @@ -423,7 +423,7 @@ class SnapshotIterator template class InlineFrameIteratorMaybeGC { - const IonFrameIterator *frame_; + const JitFrameIterator *frame_; SnapshotIterator start_; SnapshotIterator si_; uint32_t framesRead_; @@ -447,14 +447,14 @@ class InlineFrameIteratorMaybeGC void findNextFrame(); public: - InlineFrameIteratorMaybeGC(JSContext *cx, const IonFrameIterator *iter) + InlineFrameIteratorMaybeGC(JSContext *cx, const JitFrameIterator *iter) : callee_(cx), script_(cx) { resetOn(iter); } - InlineFrameIteratorMaybeGC(JSRuntime *rt, const IonFrameIterator *iter) + InlineFrameIteratorMaybeGC(JSRuntime *rt, const JitFrameIterator *iter) : callee_(rt), script_(rt) { @@ -614,9 +614,9 @@ class InlineFrameIteratorMaybeGC void dump() const; - void resetOn(const IonFrameIterator *iter); + void resetOn(const JitFrameIterator *iter); - const IonFrameIterator &frame() const { + const JitFrameIterator &frame() const { return *frame_; } @@ -638,4 +638,4 @@ typedef InlineFrameIteratorMaybeGC InlineFrameIteratorNoGC; #endif // JS_ION -#endif /* jit_IonFrameIterator_h */ +#endif /* jit_JitFrameIterator_h */ diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 6c8aefab1b6d..0dd703f432ee 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -1018,7 +1018,7 @@ Recompile(JSContext *cx) { JS_ASSERT(cx->currentlyRunningInJit()); JitActivationIterator activations(cx->runtime()); - IonFrameIterator iter(activations); + JitFrameIterator iter(activations); JS_ASSERT(iter.type() == JitFrame_Exit); ++iter; diff --git a/js/src/jit/arm/Bailouts-arm.cpp b/js/src/jit/arm/Bailouts-arm.cpp index 8fabe58efe1a..752d3bb40f6b 100644 --- a/js/src/jit/arm/Bailouts-arm.cpp +++ b/js/src/jit/arm/Bailouts-arm.cpp @@ -70,7 +70,7 @@ static_assert((sizeof(BailoutStack) % 8) == 0, "BailoutStack should be 8-byte al IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, BailoutStack *bailout) - : IonFrameIterator(activations), + : JitFrameIterator(activations), machine_(bailout->machine()) { uint8_t *sp = bailout->parentStackPointer(); @@ -105,7 +105,7 @@ IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, InvalidationBailoutStack *bailout) - : IonFrameIterator(activations), + : JitFrameIterator(activations), machine_(bailout->machine()) { returnAddressToFp_ = bailout->osiPointReturnAddress(); diff --git a/js/src/jit/x64/Bailouts-x64.cpp b/js/src/jit/x64/Bailouts-x64.cpp index 4340296f8272..9bd803e1f9cc 100644 --- a/js/src/jit/x64/Bailouts-x64.cpp +++ b/js/src/jit/x64/Bailouts-x64.cpp @@ -47,7 +47,7 @@ class BailoutStack IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, BailoutStack *bailout) - : IonFrameIterator(activations), + : JitFrameIterator(activations), machine_(bailout->machineState()) { uint8_t *sp = bailout->parentStackPointer(); @@ -62,7 +62,7 @@ IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, InvalidationBailoutStack *bailout) - : IonFrameIterator(activations), + : JitFrameIterator(activations), machine_(bailout->machine()) { returnAddressToFp_ = bailout->osiPointReturnAddress(); diff --git a/js/src/jit/x86/Bailouts-x86.cpp b/js/src/jit/x86/Bailouts-x86.cpp index bcd86692a9e8..2e0367d10822 100644 --- a/js/src/jit/x86/Bailouts-x86.cpp +++ b/js/src/jit/x86/Bailouts-x86.cpp @@ -67,7 +67,7 @@ class BailoutStack IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, BailoutStack *bailout) - : IonFrameIterator(activations), + : JitFrameIterator(activations), machine_(bailout->machine()) { uint8_t *sp = bailout->parentStackPointer(); @@ -102,7 +102,7 @@ IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations, InvalidationBailoutStack *bailout) - : IonFrameIterator(activations), + : JitFrameIterator(activations), machine_(bailout->machine()) { returnAddressToFp_ = bailout->osiPointReturnAddress(); diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 7f4639cd5f11..c01f408044c1 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -33,7 +33,7 @@ #include "gc/Marking.h" #ifdef JS_ION #include "jit/Ion.h" -#include "jit/IonFrameIterator.h" +#include "jit/JitFrameIterator.h" #endif #include "vm/Interpreter.h" #include "vm/Shape.h" diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 200d1924963d..f845735b5bb0 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -18,7 +18,7 @@ #endif #include "vm/Opcodes.h" -#include "jit/IonFrameIterator-inl.h" +#include "jit/JitFrameIterator-inl.h" #include "vm/Interpreter-inl.h" #include "vm/Probes-inl.h" #include "vm/ScopeObject-inl.h" @@ -568,7 +568,7 @@ FrameIter::settleOnActivation() #ifdef JS_ION if (activation->isJit()) { - data_.ionFrames_ = jit::IonFrameIterator(data_.activations_); + data_.ionFrames_ = jit::JitFrameIterator(data_.activations_); // Stop at the first scripted frame. while (!data_.ionFrames_.isScripted() && !data_.ionFrames_.done()) @@ -655,7 +655,7 @@ FrameIter::Data::Data(const FrameIter::Data &other) FrameIter::FrameIter(JSContext *cx, SavedOption savedOption) : data_(cx, savedOption, CURRENT_CONTEXT, nullptr) #ifdef JS_ION - , ionInlineFrames_(cx, (js::jit::IonFrameIterator*) nullptr) + , ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr) #endif { settleOnActivation(); @@ -665,7 +665,7 @@ FrameIter::FrameIter(JSContext *cx, ContextOption contextOption, SavedOption savedOption, JSPrincipals *principals) : data_(cx, savedOption, contextOption, principals) #ifdef JS_ION - , ionInlineFrames_(cx, (js::jit::IonFrameIterator*) nullptr) + , ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr) #endif { settleOnActivation(); @@ -1107,7 +1107,7 @@ FrameIter::updatePcQuadratic() ++data_.activations_; // Look for the current frame. - data_.ionFrames_ = jit::IonFrameIterator(data_.activations_); + data_.ionFrames_ = jit::JitFrameIterator(data_.activations_); while (!data_.ionFrames_.isBaselineJS() || data_.ionFrames_.baselineFrame() != frame) ++data_.ionFrames_; diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 3b325e263163..9b535fea12dc 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -12,7 +12,7 @@ #include "jsfun.h" #include "jsscript.h" -#include "jit/IonFrameIterator.h" +#include "jit/JitFrameIterator.h" #ifdef CHECK_OSIPOINT_REGISTERS #include "jit/Registers.h" // for RegisterDump #endif @@ -1515,7 +1515,7 @@ class FrameIter ActivationIterator activations_; #ifdef JS_ION - jit::IonFrameIterator ionFrames_; + jit::JitFrameIterator ionFrames_; #endif Data(JSContext *cx, SavedOption savedOption, ContextOption contextOption, From fa25dee699ada818fca11ead4b00c59a354052ee Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Wed, 23 Apr 2014 11:56:23 +0200 Subject: [PATCH 15/40] Bug 999559 part 2 - Rename FrameIter::Data::ionFrames_ to jitFrames_. r=luke --- js/src/vm/Stack-inl.h | 6 +- js/src/vm/Stack.cpp | 126 +++++++++++++++++++++--------------------- js/src/vm/Stack.h | 10 ++-- 3 files changed, 71 insertions(+), 71 deletions(-) diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index 7b4764adf1fc..6e7fca78e76f 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -338,11 +338,11 @@ FrameIter::unaliasedForEachActual(JSContext *cx, Op op) return; case JIT: #ifdef JS_ION - if (data_.ionFrames_.isIonJS()) { + if (data_.jitFrames_.isIonJS()) { ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals); } else { - JS_ASSERT(data_.ionFrames_.isBaselineJS()); - data_.ionFrames_.unaliasedForEachActual(op, jit::ReadFrame_Actuals); + JS_ASSERT(data_.jitFrames_.isBaselineJS()); + data_.jitFrames_.unaliasedForEachActual(op, jit::ReadFrame_Actuals); } return; #else diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index f845735b5bb0..26cf186230fb 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -568,15 +568,15 @@ FrameIter::settleOnActivation() #ifdef JS_ION if (activation->isJit()) { - data_.ionFrames_ = jit::JitFrameIterator(data_.activations_); + data_.jitFrames_ = jit::JitFrameIterator(data_.activations_); // Stop at the first scripted frame. - while (!data_.ionFrames_.isScripted() && !data_.ionFrames_.done()) - ++data_.ionFrames_; + while (!data_.jitFrames_.isScripted() && !data_.jitFrames_.done()) + ++data_.jitFrames_; // It's possible to have an JitActivation with no scripted frames, // for instance if we hit an over-recursion during bailout. - if (data_.ionFrames_.done()) { + if (data_.jitFrames_.done()) { ++data_.activations_; continue; } @@ -632,7 +632,7 @@ FrameIter::Data::Data(JSContext *cx, SavedOption savedOption, ContextOption cont interpFrames_(nullptr), activations_(cx->runtime()) #ifdef JS_ION - , ionFrames_((uint8_t *)nullptr, SequentialExecution) + , jitFrames_((uint8_t *)nullptr, SequentialExecution) #endif { } @@ -647,7 +647,7 @@ FrameIter::Data::Data(const FrameIter::Data &other) interpFrames_(other.interpFrames_), activations_(other.activations_) #ifdef JS_ION - , ionFrames_(other.ionFrames_) + , jitFrames_(other.jitFrames_) #endif { } @@ -675,7 +675,7 @@ FrameIter::FrameIter(const FrameIter &other) : data_(other.data_) #ifdef JS_ION , ionInlineFrames_(other.data_.cx_, - data_.ionFrames_.isScripted() ? &other.ionInlineFrames_ : nullptr) + data_.jitFrames_.isScripted() ? &other.ionInlineFrames_ : nullptr) #endif { } @@ -683,7 +683,7 @@ FrameIter::FrameIter(const FrameIter &other) FrameIter::FrameIter(const Data &data) : data_(data) #ifdef JS_ION - , ionInlineFrames_(data.cx_, data_.ionFrames_.isIonJS() ? &data_.ionFrames_ : nullptr) + , ionInlineFrames_(data.cx_, data_.jitFrames_.isIonJS() ? &data_.jitFrames_ : nullptr) #endif { JS_ASSERT(data.cx_); @@ -693,12 +693,12 @@ FrameIter::FrameIter(const Data &data) void FrameIter::nextJitFrame() { - if (data_.ionFrames_.isIonJS()) { - ionInlineFrames_.resetOn(&data_.ionFrames_); + if (data_.jitFrames_.isIonJS()) { + ionInlineFrames_.resetOn(&data_.jitFrames_); data_.pc_ = ionInlineFrames_.pc(); } else { - JS_ASSERT(data_.ionFrames_.isBaselineJS()); - data_.ionFrames_.baselineScriptAndPc(nullptr, &data_.pc_); + JS_ASSERT(data_.jitFrames_.isBaselineJS()); + data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_); } } @@ -707,17 +707,17 @@ FrameIter::popJitFrame() { JS_ASSERT(data_.state_ == JIT); - if (data_.ionFrames_.isIonJS() && ionInlineFrames_.more()) { + if (data_.jitFrames_.isIonJS() && ionInlineFrames_.more()) { ++ionInlineFrames_; data_.pc_ = ionInlineFrames_.pc(); return; } - ++data_.ionFrames_; - while (!data_.ionFrames_.done() && !data_.ionFrames_.isScripted()) - ++data_.ionFrames_; + ++data_.jitFrames_; + while (!data_.jitFrames_.done() && !data_.jitFrames_.isScripted()) + ++data_.jitFrames_; - if (!data_.ionFrames_.done()) { + if (!data_.jitFrames_.done()) { nextJitFrame(); return; } @@ -791,7 +791,7 @@ FrameIter::copyData() const * not copied. */ JS_ASSERT(data_.state_ != ASMJS); - JS_ASSERT(data_.ionFrames_.type() != jit::JitFrame_IonJS); + JS_ASSERT(data_.jitFrames_.type() != jit::JitFrame_IonJS); #endif return data_.cx_->new_(data_); } @@ -829,9 +829,9 @@ FrameIter::isFunctionFrame() const return interpFrame()->isFunctionFrame(); case JIT: #ifdef JS_ION - JS_ASSERT(data_.ionFrames_.isScripted()); - if (data_.ionFrames_.isBaselineJS()) - return data_.ionFrames_.isFunctionFrame(); + JS_ASSERT(data_.jitFrames_.isScripted()); + if (data_.jitFrames_.isBaselineJS()) + return data_.jitFrames_.isFunctionFrame(); return ionInlineFrames_.isFunctionFrame(); #else break; @@ -852,8 +852,8 @@ FrameIter::isGlobalFrame() const return interpFrame()->isGlobalFrame(); case JIT: #ifdef JS_ION - if (data_.ionFrames_.isBaselineJS()) - return data_.ionFrames_.baselineFrame()->isGlobalFrame(); + if (data_.jitFrames_.isBaselineJS()) + return data_.jitFrames_.baselineFrame()->isGlobalFrame(); JS_ASSERT(!script()->isForEval()); return !script()->functionNonDelazifying(); #else @@ -875,8 +875,8 @@ FrameIter::isEvalFrame() const return interpFrame()->isEvalFrame(); case JIT: #ifdef JS_ION - if (data_.ionFrames_.isBaselineJS()) - return data_.ionFrames_.baselineFrame()->isEvalFrame(); + if (data_.jitFrames_.isBaselineJS()) + return data_.jitFrames_.baselineFrame()->isEvalFrame(); JS_ASSERT(!script()->isForEval()); return false; #else @@ -1040,10 +1040,10 @@ FrameIter::isConstructing() const break; case JIT: #ifdef JS_ION - if (data_.ionFrames_.isIonJS()) + if (data_.jitFrames_.isIonJS()) return ionInlineFrames_.isConstructing(); - JS_ASSERT(data_.ionFrames_.isBaselineJS()); - return data_.ionFrames_.isConstructing(); + JS_ASSERT(data_.jitFrames_.isBaselineJS()); + return data_.jitFrames_.isConstructing(); #else break; #endif @@ -1062,8 +1062,8 @@ FrameIter::abstractFramePtr() const break; case JIT: #ifdef JS_ION - if (data_.ionFrames_.isBaselineJS()) - return data_.ionFrames_.baselineFrame(); + if (data_.jitFrames_.isBaselineJS()) + return data_.jitFrames_.baselineFrame(); #endif break; case INTERP: @@ -1096,8 +1096,8 @@ FrameIter::updatePcQuadratic() } case JIT: #ifdef JS_ION - if (data_.ionFrames_.isBaselineJS()) { - jit::BaselineFrame *frame = data_.ionFrames_.baselineFrame(); + if (data_.jitFrames_.isBaselineJS()) { + jit::BaselineFrame *frame = data_.jitFrames_.baselineFrame(); jit::JitActivation *activation = data_.activations_.activation()->asJit(); // ActivationIterator::ionTop_ may be invalid, so create a new @@ -1107,13 +1107,13 @@ FrameIter::updatePcQuadratic() ++data_.activations_; // Look for the current frame. - data_.ionFrames_ = jit::JitFrameIterator(data_.activations_); - while (!data_.ionFrames_.isBaselineJS() || data_.ionFrames_.baselineFrame() != frame) - ++data_.ionFrames_; + data_.jitFrames_ = jit::JitFrameIterator(data_.activations_); + while (!data_.jitFrames_.isBaselineJS() || data_.jitFrames_.baselineFrame() != frame) + ++data_.jitFrames_; // Update the pc. - JS_ASSERT(data_.ionFrames_.baselineFrame() == frame); - data_.ionFrames_.baselineScriptAndPc(nullptr, &data_.pc_); + JS_ASSERT(data_.jitFrames_.baselineFrame() == frame); + data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_); return; } #endif @@ -1134,9 +1134,9 @@ FrameIter::callee() const return &interpFrame()->callee(); case JIT: #ifdef JS_ION - if (data_.ionFrames_.isBaselineJS()) - return data_.ionFrames_.callee(); - JS_ASSERT(data_.ionFrames_.isIonJS()); + if (data_.jitFrames_.isBaselineJS()) + return data_.jitFrames_.callee(); + JS_ASSERT(data_.jitFrames_.isIonJS()); return ionInlineFrames_.callee(); #else break; @@ -1177,11 +1177,11 @@ FrameIter::numActualArgs() const return interpFrame()->numActualArgs(); case JIT: #ifdef JS_ION - if (data_.ionFrames_.isIonJS()) + if (data_.jitFrames_.isIonJS()) return ionInlineFrames_.numActualArgs(); - JS_ASSERT(data_.ionFrames_.isBaselineJS()); - return data_.ionFrames_.numActualArgs(); + JS_ASSERT(data_.jitFrames_.isBaselineJS()); + return data_.jitFrames_.numActualArgs(); #else break; #endif @@ -1206,8 +1206,8 @@ FrameIter::unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing) const return interpFrame()->unaliasedActual(i, checkAliasing); case JIT: #ifdef JS_ION - JS_ASSERT(data_.ionFrames_.isBaselineJS()); - return data_.ionFrames_.baselineFrame()->unaliasedActual(i, checkAliasing); + JS_ASSERT(data_.jitFrames_.isBaselineJS()); + return data_.jitFrames_.baselineFrame()->unaliasedActual(i, checkAliasing); #else break; #endif @@ -1224,9 +1224,9 @@ FrameIter::scopeChain() const break; case JIT: #ifdef JS_ION - if (data_.ionFrames_.isIonJS()) + if (data_.jitFrames_.isIonJS()) return ionInlineFrames_.scopeChain(); - return data_.ionFrames_.baselineFrame()->scopeChain(); + return data_.jitFrames_.baselineFrame()->scopeChain(); #else break; #endif @@ -1258,8 +1258,8 @@ FrameIter::hasArgsObj() const return interpFrame()->hasArgsObj(); case JIT: #ifdef JS_ION - JS_ASSERT(data_.ionFrames_.isBaselineJS()); - return data_.ionFrames_.baselineFrame()->hasArgsObj(); + JS_ASSERT(data_.jitFrames_.isBaselineJS()); + return data_.jitFrames_.baselineFrame()->hasArgsObj(); #else break; #endif @@ -1278,8 +1278,8 @@ FrameIter::argsObj() const break; case JIT: #ifdef JS_ION - JS_ASSERT(data_.ionFrames_.isBaselineJS()); - return data_.ionFrames_.baselineFrame()->argsObj(); + JS_ASSERT(data_.jitFrames_.isBaselineJS()); + return data_.jitFrames_.baselineFrame()->argsObj(); #else break; #endif @@ -1309,9 +1309,9 @@ FrameIter::thisv() const break; case JIT: #ifdef JS_ION - if (data_.ionFrames_.isIonJS()) + if (data_.jitFrames_.isIonJS()) return ObjectValue(*ionInlineFrames_.thisObject()); - return data_.ionFrames_.baselineFrame()->thisValue(); + return data_.jitFrames_.baselineFrame()->thisValue(); #else break; #endif @@ -1330,8 +1330,8 @@ FrameIter::returnValue() const break; case JIT: #ifdef JS_ION - if (data_.ionFrames_.isBaselineJS()) - return data_.ionFrames_.baselineFrame()->returnValue(); + if (data_.jitFrames_.isBaselineJS()) + return data_.jitFrames_.baselineFrame()->returnValue(); #endif break; case INTERP: @@ -1349,8 +1349,8 @@ FrameIter::setReturnValue(const Value &v) break; case JIT: #ifdef JS_ION - if (data_.ionFrames_.isBaselineJS()) { - data_.ionFrames_.baselineFrame()->setReturnValue(v); + if (data_.jitFrames_.isBaselineJS()) { + data_.jitFrames_.baselineFrame()->setReturnValue(v); return; } #endif @@ -1371,12 +1371,12 @@ FrameIter::numFrameSlots() const break; case JIT: { #ifdef JS_ION - if (data_.ionFrames_.isIonJS()) { + if (data_.jitFrames_.isIonJS()) { return ionInlineFrames_.snapshotIterator().numAllocations() - ionInlineFrames_.script()->nfixed(); } - jit::BaselineFrame *frame = data_.ionFrames_.baselineFrame(); - return frame->numValueSlots() - data_.ionFrames_.script()->nfixed(); + jit::BaselineFrame *frame = data_.jitFrames_.baselineFrame(); + return frame->numValueSlots() - data_.jitFrames_.script()->nfixed(); #else break; #endif @@ -1397,14 +1397,14 @@ FrameIter::frameSlotValue(size_t index) const break; case JIT: #ifdef JS_ION - if (data_.ionFrames_.isIonJS()) { + if (data_.jitFrames_.isIonJS()) { jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator()); index += ionInlineFrames_.script()->nfixed(); return si.maybeReadAllocByIndex(index); } - index += data_.ionFrames_.script()->nfixed(); - return *data_.ionFrames_.baselineFrame()->valueSlot(index); + index += data_.jitFrames_.script()->nfixed(); + return *data_.jitFrames_.baselineFrame()->valueSlot(index); #else break; #endif diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 9b535fea12dc..974c8c08a9cc 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1515,7 +1515,7 @@ class FrameIter ActivationIterator activations_; #ifdef JS_ION - jit::JitFrameIterator ionFrames_; + jit::JitFrameIterator jitFrames_; #endif Data(JSContext *cx, SavedOption savedOption, ContextOption contextOption, @@ -1758,9 +1758,9 @@ FrameIter::script() const return interpFrame()->script(); #ifdef JS_ION JS_ASSERT(data_.state_ == JIT); - if (data_.ionFrames_.isIonJS()) + if (data_.jitFrames_.isIonJS()) return ionInlineFrames_.script(); - return data_.ionFrames_.script(); + return data_.jitFrames_.script(); #else return nullptr; #endif @@ -1770,7 +1770,7 @@ inline bool FrameIter::isIon() const { #ifdef JS_ION - return isJit() && data_.ionFrames_.isIonJS(); + return isJit() && data_.jitFrames_.isIonJS(); #else return false; #endif @@ -1780,7 +1780,7 @@ inline bool FrameIter::isBaseline() const { #ifdef JS_ION - return isJit() && data_.ionFrames_.isBaselineJS(); + return isJit() && data_.jitFrames_.isBaselineJS(); #else return false; #endif From 30a263d4bd9ac9f4b463ff3b667f6e7dfafea40d Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 23 Apr 2014 14:19:29 +0200 Subject: [PATCH 16/40] Bug 999736 - Add a null check in ContentHostTexture::Lock. r=bjacob --- gfx/layers/composite/ContentHost.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gfx/layers/composite/ContentHost.h b/gfx/layers/composite/ContentHost.h index 67ba02cf9688..e110f1f63738 100644 --- a/gfx/layers/composite/ContentHost.h +++ b/gfx/layers/composite/ContentHost.h @@ -152,6 +152,9 @@ public: virtual bool Lock() { MOZ_ASSERT(!mLocked); + if (!mTextureHost) { + return false; + } if (!mTextureHost->Lock()) { return false; } From 50f3f3bd9eacd33896cb6fc9dbb9add0c696fd9a Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Wed, 23 Apr 2014 13:34:14 +0100 Subject: [PATCH 17/40] bug 998777 - use Nirmala UI by default for Devanagari text on Windows. r=smontagu --- gfx/thebes/gfxWindowsPlatform.cpp | 1 + modules/libpref/src/init/all.js | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index b2fd310ac095..831d086d5e8b 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -804,6 +804,7 @@ gfxWindowsPlatform::GetCommonFallbackFonts(const uint32_t aCh, aFontList.AppendElement(kFontEbrima); break; case 0x09: + aFontList.AppendElement(kFontNirmalaUI); aFontList.AppendElement(kFontUtsaah); aFontList.AppendElement(kFontAparajita); break; diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 72e4095ae2f8..d5f61766e753 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -2323,11 +2323,12 @@ pref("font.name-list.serif.zh-HK", "MingLiu_HKSCS, Ming(for ISO10646), MingLiU, pref("font.name-list.sans-serif.zh-HK", "MingLiU_HKSCS, Ming(for ISO10646), MingLiU, MingLiU_HKSCS-ExtB"); pref("font.name-list.monospace.zh-HK", "MingLiU_HKSCS, Ming(for ISO10646), MingLiU, MingLiU_HKSCS-ExtB"); -pref("font.name.serif.x-devanagari", "Mangal"); -pref("font.name.sans-serif.x-devanagari", "Raghindi"); +pref("font.name.serif.x-devanagari", "Kokila"); +pref("font.name.sans-serif.x-devanagari", "Nirmala UI"); pref("font.name.monospace.x-devanagari", "Mangal"); -pref("font.name-list.serif.x-devanagari", "Mangal, Raghindi"); -pref("font.name-list.monospace.x-devanagari", "Mangal, Raghindi"); +pref("font.name-list.serif.x-devanagari", "Kokila, Raghindi"); +pref("font.name-list.sans-serif.x-devanagari", "Nirmala UI, Mangal"); +pref("font.name-list.monospace.x-devanagari", "Mangal, Nirmala UI"); pref("font.name.serif.x-tamil", "Latha"); pref("font.name.sans-serif.x-tamil", "Code2000"); @@ -2470,7 +2471,7 @@ pref("font.default.x-cyrillic", "serif"); pref("font.size.variable.x-cyrillic", 16); pref("font.size.fixed.x-cyrillic", 13); -pref("font.default.x-devanagari", "serif"); +pref("font.default.x-devanagari", "sans-serif"); pref("font.size.variable.x-devanagari", 16); pref("font.size.fixed.x-devanagari", 13); From 0d8a56a9e23a96f41218994101a65ef3df6da957 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 23 Apr 2014 13:48:34 +0100 Subject: [PATCH 18/40] Bug 988950 - Check whether value is an object after checking whether object is in nursery r=terrence --- js/src/jit/CodeGenerator.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 5310b206cde8..cd48e5969f7c 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -1861,9 +1861,6 @@ CodeGenerator::visitPostWriteBarrierV(LPostWriteBarrierV *lir) if (!addOutOfLineCode(ool)) return false; - ValueOperand value = ToValue(lir, LPostWriteBarrierV::Input); - masm.branchTestObject(Assembler::NotEqual, value, ool->rejoin()); - const Nursery &nursery = GetIonContext()->runtime->gcNursery(); if (lir->object()->isConstant()) { @@ -1876,6 +1873,9 @@ CodeGenerator::visitPostWriteBarrierV(LPostWriteBarrierV *lir) masm.branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), ool->rejoin()); } + ValueOperand value = ToValue(lir, LPostWriteBarrierV::Input); + masm.branchTestObject(Assembler::NotEqual, value, ool->rejoin()); + // This section is a little different because we mustn't trash the temp // register before we use its contents. Register temp = ToRegister(lir->temp()); From 7192a5c41175f085a902bc4dfd06a7142d6e7ddd Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 23 Apr 2014 13:48:35 +0100 Subject: [PATCH 19/40] Bug 988950 - Add a macro assembler instruction to check if a pointer is in the nursery r=jandem --- js/src/jit/BaselineCompiler.cpp | 13 ++++------- js/src/jit/BaselineIC.cpp | 5 +---- js/src/jit/CodeGenerator.cpp | 30 ++++++-------------------- js/src/jit/IonMacroAssembler.cpp | 37 ++++++++++++++++++++++++++++++++ js/src/jit/IonMacroAssembler.h | 5 +++++ 5 files changed, 54 insertions(+), 36 deletions(-) diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index e886cf2373c6..5b7b948443a2 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -416,7 +416,6 @@ BaselineCompiler::emitEpilogue() #ifdef JSGC_GENERATIONAL // On input: // R2.scratchReg() contains object being written to. -// R1.scratchReg() contains slot index being written to. // Otherwise, baseline stack will be synced, so all other registers are usable as scratch. // This calls: // void PostWriteBarrier(JSRuntime *rt, JSObject *obj); @@ -2101,15 +2100,13 @@ BaselineCompiler::emit_JSOP_SETALIASEDVAR() // Fully sync the stack if post-barrier is needed. // Scope coordinate object is already in R2.scratchReg(). frame.syncStack(0); + Register temp = R1.scratchReg(); Nursery &nursery = cx->runtime()->gcNursery; Label skipBarrier; - Label isTenured; masm.branchTestObject(Assembler::NotEqual, R0, &skipBarrier); - masm.branchPtr(Assembler::Below, objReg, ImmWord(nursery.start()), &isTenured); - masm.branchPtr(Assembler::Below, objReg, ImmWord(nursery.heapEnd()), &skipBarrier); + masm.branchPtrInNurseryRange(objReg, temp, &skipBarrier); - masm.bind(&isTenured); masm.call(&postBarrierSlot_); masm.bind(&skipBarrier); @@ -2419,6 +2416,7 @@ BaselineCompiler::emitFormalArgAccess(uint32_t arg, bool get) #ifdef JSGC_GENERATIONAL // Fully sync the stack if post-barrier is needed. frame.syncStack(0); + Register temp = R1.scratchReg(); // Reload the arguments object Register reg = R2.scratchReg(); @@ -2426,11 +2424,8 @@ BaselineCompiler::emitFormalArgAccess(uint32_t arg, bool get) Nursery &nursery = cx->runtime()->gcNursery; Label skipBarrier; - Label isTenured; - masm.branchPtr(Assembler::Below, reg, ImmWord(nursery.start()), &isTenured); - masm.branchPtr(Assembler::Below, reg, ImmWord(nursery.heapEnd()), &skipBarrier); + masm.branchPtrInNurseryRange(reg, temp, &skipBarrier); - masm.bind(&isTenured); masm.call(&postBarrierSlot_); masm.bind(&skipBarrier); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 2d550700ad21..ed9450807869 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -738,10 +738,7 @@ ICStubCompiler::emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, Val Label skipBarrier; masm.branchTestObject(Assembler::NotEqual, val, &skipBarrier); - Label isTenured; - masm.branchPtr(Assembler::Below, obj, ImmWord(nursery.start()), &isTenured); - masm.branchPtr(Assembler::Below, obj, ImmWord(nursery.heapEnd()), &skipBarrier); - masm.bind(&isTenured); + masm.branchPtrInNurseryRange(obj, scratch, &skipBarrier); Register valReg = masm.extractObject(val, scratch); masm.branchPtr(Assembler::Below, valReg, ImmWord(nursery.start()), &skipBarrier); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index cd48e5969f7c..7fe1b0817c05 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -1831,22 +1831,16 @@ CodeGenerator::visitPostWriteBarrierO(LPostWriteBarrierO *lir) if (!addOutOfLineCode(ool)) return false; - const Nursery &nursery = GetIonContext()->runtime->gcNursery(); Register temp = ToRegister(lir->temp()); if (lir->object()->isConstant()) { + const Nursery &nursery = GetIonContext()->runtime->gcNursery(); JS_ASSERT(!nursery.isInside(&lir->object()->toConstant()->toObject())); } else { - Register objreg = ToRegister(lir->object()); - masm.movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); - masm.addPtr(objreg, temp); - masm.branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), ool->rejoin()); + masm.branchPtrInNurseryRange(ToRegister(lir->object()), temp, ool->rejoin()); } - Register valuereg = ToRegister(lir->value()); - masm.movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); - masm.addPtr(valuereg, temp); - masm.branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), ool->entry()); + masm.branchPtrInNurseryRange(ToRegister(lir->value()), temp, ool->entry()); masm.bind(ool->rejoin()); #endif @@ -1861,27 +1855,17 @@ CodeGenerator::visitPostWriteBarrierV(LPostWriteBarrierV *lir) if (!addOutOfLineCode(ool)) return false; - const Nursery &nursery = GetIonContext()->runtime->gcNursery(); + Register temp = ToRegister(lir->temp()); if (lir->object()->isConstant()) { + const Nursery &nursery = GetIonContext()->runtime->gcNursery(); JS_ASSERT(!nursery.isInside(&lir->object()->toConstant()->toObject())); } else { - Register temp = ToRegister(lir->temp()); - Register objreg = ToRegister(lir->object()); - masm.movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); - masm.addPtr(objreg, temp); - masm.branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), ool->rejoin()); + masm.branchPtrInNurseryRange(ToRegister(lir->object()), temp, ool->rejoin()); } ValueOperand value = ToValue(lir, LPostWriteBarrierV::Input); - masm.branchTestObject(Assembler::NotEqual, value, ool->rejoin()); - - // This section is a little different because we mustn't trash the temp - // register before we use its contents. - Register temp = ToRegister(lir->temp()); - masm.unboxObject(value, temp); - masm.addPtr(ImmWord(-ptrdiff_t(nursery.start())), temp); - masm.branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), ool->entry()); + masm.branchValueIsNurseryObject(value, temp, ool->entry()); masm.bind(ool->rejoin()); #endif diff --git a/js/src/jit/IonMacroAssembler.cpp b/js/src/jit/IonMacroAssembler.cpp index 2326fe1611da..69fae430998c 100644 --- a/js/src/jit/IonMacroAssembler.cpp +++ b/js/src/jit/IonMacroAssembler.cpp @@ -1786,3 +1786,40 @@ MacroAssembler::spsUnmarkJit(SPSProfiler *p, Register temp) bind(&spsNotEnabled); } + +#ifdef JSGC_GENERATIONAL + +void +MacroAssembler::branchPtrInNurseryRange(Register ptr, Register temp, Label *label) +{ + JS_ASSERT(ptr != temp); + JS_ASSERT(temp != InvalidReg); + + const Nursery &nursery = GetIonContext()->runtime->gcNursery(); + movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); + addPtr(ptr, temp); + branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), label); +} + +void +MacroAssembler::branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label) +{ + Label done; + + branchTestObject(Assembler::NotEqual, value, &done); + + Register obj = extractObject(value, temp); + // valobj and temp may be the same register, in which case we mustn't trash it + // before we use its contents. + if (obj == temp) { + const Nursery &nursery = GetIonContext()->runtime->gcNursery(); + addPtr(ImmWord(-ptrdiff_t(nursery.start())), obj); + branchPtr(Assembler::Below, obj, Imm32(Nursery::NurserySize), label); + } else { + branchPtrInNurseryRange(obj, temp, label); + } + + bind(&done); +} + +#endif diff --git a/js/src/jit/IonMacroAssembler.h b/js/src/jit/IonMacroAssembler.h index 542f0418a757..0ff8fe6a871a 100644 --- a/js/src/jit/IonMacroAssembler.h +++ b/js/src/jit/IonMacroAssembler.h @@ -1352,6 +1352,11 @@ class MacroAssembler : public MacroAssemblerSpecific convertTypedOrValueToInt(src, temp, output, fail, IntConversion_ClampToUint8); } +#ifdef JSGC_GENERATIONAL + void branchPtrInNurseryRange(Register ptr, Register temp, Label *label); + void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label); +#endif + public: class AfterICSaveLive { friend class MacroAssembler; From f576917080d50d7b45c88f636a0d3681ef19d0f5 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 23 Apr 2014 13:48:35 +0100 Subject: [PATCH 20/40] Bug 988950 - Split macro assembler implementation by architecture r=jandem --- js/src/gc/Nursery.h | 23 +++++++-------- js/src/jit/IonMacroAssembler.cpp | 37 ------------------------- js/src/jit/IonMacroAssembler.h | 5 ---- js/src/jit/arm/MacroAssembler-arm.cpp | 36 ++++++++++++++++++++++++ js/src/jit/arm/MacroAssembler-arm.h | 5 ++++ js/src/jit/mips/MacroAssembler-mips.cpp | 18 ++++++++++++ js/src/jit/mips/MacroAssembler-mips.h | 2 ++ js/src/jit/x64/MacroAssembler-x64.cpp | 37 +++++++++++++++++++++++++ js/src/jit/x64/MacroAssembler-x64.h | 4 +++ js/src/jit/x86/MacroAssembler-x86.cpp | 37 +++++++++++++++++++++++++ js/src/jit/x86/MacroAssembler-x86.h | 5 ++++ 11 files changed, 154 insertions(+), 55 deletions(-) diff --git a/js/src/gc/Nursery.h b/js/src/gc/Nursery.h index f73017625d49..b28a56f01c1a 100644 --- a/js/src/gc/Nursery.h +++ b/js/src/gc/Nursery.h @@ -139,6 +139,16 @@ class Nursery return total; } + MOZ_ALWAYS_INLINE uintptr_t start() const { + JS_ASSERT(runtime_); + return ((JS::shadow::Runtime *)runtime_)->gcNurseryStart_; + } + + MOZ_ALWAYS_INLINE uintptr_t heapEnd() const { + JS_ASSERT(runtime_); + return ((JS::shadow::Runtime *)runtime_)->gcNurseryEnd_; + } + private: /* * The start and end pointers are stored under the runtime so that we can @@ -190,16 +200,6 @@ class Nursery return reinterpret_cast(start())[index]; } - MOZ_ALWAYS_INLINE uintptr_t start() const { - JS_ASSERT(runtime_); - return ((JS::shadow::Runtime *)runtime_)->gcNurseryStart_; - } - - MOZ_ALWAYS_INLINE uintptr_t heapEnd() const { - JS_ASSERT(runtime_); - return ((JS::shadow::Runtime *)runtime_)->gcNurseryEnd_; - } - MOZ_ALWAYS_INLINE void setCurrentChunk(int chunkno) { JS_ASSERT(chunkno < NumNurseryChunks); JS_ASSERT(chunkno < numActiveChunks_); @@ -314,10 +314,7 @@ class Nursery #endif friend class gc::MinorCollectionTracer; - friend class jit::CodeGenerator; friend class jit::MacroAssembler; - friend class jit::ICStubCompiler; - friend class jit::BaselineCompiler; friend void SetGCZeal(JSRuntime *, uint8_t, uint32_t); }; diff --git a/js/src/jit/IonMacroAssembler.cpp b/js/src/jit/IonMacroAssembler.cpp index 69fae430998c..2326fe1611da 100644 --- a/js/src/jit/IonMacroAssembler.cpp +++ b/js/src/jit/IonMacroAssembler.cpp @@ -1786,40 +1786,3 @@ MacroAssembler::spsUnmarkJit(SPSProfiler *p, Register temp) bind(&spsNotEnabled); } - -#ifdef JSGC_GENERATIONAL - -void -MacroAssembler::branchPtrInNurseryRange(Register ptr, Register temp, Label *label) -{ - JS_ASSERT(ptr != temp); - JS_ASSERT(temp != InvalidReg); - - const Nursery &nursery = GetIonContext()->runtime->gcNursery(); - movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); - addPtr(ptr, temp); - branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), label); -} - -void -MacroAssembler::branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label) -{ - Label done; - - branchTestObject(Assembler::NotEqual, value, &done); - - Register obj = extractObject(value, temp); - // valobj and temp may be the same register, in which case we mustn't trash it - // before we use its contents. - if (obj == temp) { - const Nursery &nursery = GetIonContext()->runtime->gcNursery(); - addPtr(ImmWord(-ptrdiff_t(nursery.start())), obj); - branchPtr(Assembler::Below, obj, Imm32(Nursery::NurserySize), label); - } else { - branchPtrInNurseryRange(obj, temp, label); - } - - bind(&done); -} - -#endif diff --git a/js/src/jit/IonMacroAssembler.h b/js/src/jit/IonMacroAssembler.h index 0ff8fe6a871a..542f0418a757 100644 --- a/js/src/jit/IonMacroAssembler.h +++ b/js/src/jit/IonMacroAssembler.h @@ -1352,11 +1352,6 @@ class MacroAssembler : public MacroAssemblerSpecific convertTypedOrValueToInt(src, temp, output, fail, IntConversion_ClampToUint8); } -#ifdef JSGC_GENERATIONAL - void branchPtrInNurseryRange(Register ptr, Register temp, Label *label); - void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label); -#endif - public: class AfterICSaveLive { friend class MacroAssembler; diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 57533058ff86..3634b39739d5 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -4334,3 +4334,39 @@ MacroAssemblerARMCompat::jumpWithPatch(RepatchLabel *label, Condition cond) return ret; } +#ifdef JSGC_GENERATIONAL + +void +MacroAssemblerARMCompat::branchPtrInNurseryRange(Register ptr, Register temp, Label *label) +{ + JS_ASSERT(ptr != temp); + JS_ASSERT(temp != InvalidReg); + + const Nursery &nursery = GetIonContext()->runtime->gcNursery(); + movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); + addPtr(ptr, temp); + branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), label); +} + +void +MacroAssemblerARMCompat::branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label) +{ + Label done; + + branchTestObject(Assembler::NotEqual, value, &done); + + Register obj = extractObject(value, temp); + // valobj and temp may be the same register, in which case we mustn't trash it + // before we use its contents. + if (obj == temp) { + const Nursery &nursery = GetIonContext()->runtime->gcNursery(); + addPtr(ImmWord(-ptrdiff_t(nursery.start())), obj); + branchPtr(Assembler::Below, obj, Imm32(Nursery::NurserySize), label); + } else { + branchPtrInNurseryRange(obj, temp, label); + } + + bind(&done); +} + +#endif diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 7c30c987f575..c22383c0aad7 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1559,6 +1559,11 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void moveFloat32(FloatRegister src, FloatRegister dest) { as_vmov(VFPRegister(src).singleOverlay(), VFPRegister(dest).singleOverlay()); } + +#ifdef JSGC_GENERATIONAL + void branchPtrInNurseryRange(Register ptr, Register temp, Label *label); + void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label); +#endif }; typedef MacroAssemblerARMCompat MacroAssemblerSpecific; diff --git a/js/src/jit/mips/MacroAssembler-mips.cpp b/js/src/jit/mips/MacroAssembler-mips.cpp index 4cb9a129d4d2..04bc2e4b58ab 100644 --- a/js/src/jit/mips/MacroAssembler-mips.cpp +++ b/js/src/jit/mips/MacroAssembler-mips.cpp @@ -3245,3 +3245,21 @@ MacroAssemblerMIPSCompat::toggledCall(JitCode *target, bool enabled) MOZ_ASSERT(nextOffset().getOffset() - offset.offset() == ToggledCallSize()); return offset; } + +void +MacroAssemblerMIPSCompat::branchPtrInNurseryRange(Register ptr, Register temp, Label *label) +{ + JS_ASSERT(temp != InvalidReg); + const Nursery &nursery = GetIonContext()->runtime->gcNursery(); + + // ptr and temp may be the same register, in which case we mustn't trash it + // before we use its contents. + if (ptr == temp) { + addPtr(ImmWord(-ptrdiff_t(nursery.start())), ptr); + branchPtr(Assembler::Below, ptr, Imm32(Nursery::NurserySize), label); + } else { + movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); + addPtr(ptr, temp); + branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), label); + } +} diff --git a/js/src/jit/mips/MacroAssembler-mips.h b/js/src/jit/mips/MacroAssembler-mips.h index c4ff62f669b7..e633dddde101 100644 --- a/js/src/jit/mips/MacroAssembler-mips.h +++ b/js/src/jit/mips/MacroAssembler-mips.h @@ -1142,6 +1142,8 @@ public: void moveFloat32(FloatRegister src, FloatRegister dest) { as_movs(dest, src); } + + void branchPtrInNurseryRange(Register ptr, Register temp, Label *label); }; typedef MacroAssemblerMIPSCompat MacroAssemblerSpecific; diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp index f61ee9866b02..ccc39b9ea8f2 100644 --- a/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -382,3 +382,40 @@ MacroAssemblerX64::testNegativeZeroFloat32(const FloatRegister ®, const Regis cmpl(scratch, Imm32(1)); return Overflow; } + +#ifdef JSGC_GENERATIONAL + +void +MacroAssemblerX64::branchPtrInNurseryRange(Register ptr, Register temp, Label *label) +{ + JS_ASSERT(ptr != temp); + JS_ASSERT(temp != InvalidReg); + + const Nursery &nursery = GetIonContext()->runtime->gcNursery(); + movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); + addPtr(ptr, temp); + branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), label); +} + +void +MacroAssemblerX64::branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label) +{ + Label done; + + branchTestObject(Assembler::NotEqual, value, &done); + + Register obj = extractObject(value, temp); + // valobj and temp may be the same register, in which case we mustn't trash it + // before we use its contents. + if (obj == temp) { + const Nursery &nursery = GetIonContext()->runtime->gcNursery(); + addPtr(ImmWord(-ptrdiff_t(nursery.start())), obj); + branchPtr(Assembler::Below, obj, Imm32(Nursery::NurserySize), label); + } else { + branchPtrInNurseryRange(obj, temp, label); + } + + bind(&done); +} + +#endif diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index 0cce56f1cd61..c239b3895196 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -1325,6 +1325,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared storeValue(JSVAL_TYPE_INT32, ScratchReg, Dest); } +#ifdef JSGC_GENERATIONAL + void branchPtrInNurseryRange(Register ptr, Register temp, Label *label); + void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label); +#endif }; typedef MacroAssemblerX64 MacroAssemblerSpecific; diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index 4b0a2e3c49cb..cfc8147bb367 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -427,3 +427,40 @@ MacroAssemblerX86::testNegativeZeroFloat32(const FloatRegister ®, const Regis cmpl(scratch, Imm32(1)); return Overflow; } + +#ifdef JSGC_GENERATIONAL + +void +MacroAssemblerX86::branchPtrInNurseryRange(Register ptr, Register temp, Label *label) +{ + JS_ASSERT(ptr != temp); + JS_ASSERT(temp != InvalidReg); + + const Nursery &nursery = GetIonContext()->runtime->gcNursery(); + movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); + addPtr(ptr, temp); + branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), label); +} + +void +MacroAssemblerX86::branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label) +{ + Label done; + + branchTestObject(Assembler::NotEqual, value, &done); + + Register obj = extractObject(value, temp); + // valobj and temp may be the same register, in which case we mustn't trash it + // before we use its contents. + if (obj == temp) { + const Nursery &nursery = GetIonContext()->runtime->gcNursery(); + addPtr(ImmWord(-ptrdiff_t(nursery.start())), obj); + branchPtr(Assembler::Below, obj, Imm32(Nursery::NurserySize), label); + } else { + branchPtrInNurseryRange(obj, temp, label); + } + + bind(&done); +} + +#endif diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 541dcfecbf8f..bcba6d478b48 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -1114,6 +1114,11 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared void linkParallelExitFrame(const Register &pt) { movl(StackPointer, Operand(pt, offsetof(PerThreadData, ionTop))); } + +#ifdef JSGC_GENERATIONAL + void branchPtrInNurseryRange(Register ptr, Register temp, Label *label); + void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label); +#endif }; typedef MacroAssemblerX86 MacroAssemblerSpecific; From c4cd68db814a460a2e472e746170edf9aea04d9f Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 23 Apr 2014 13:48:35 +0100 Subject: [PATCH 21/40] Bug 988950 - Use scratch register instead of temp where possible r=jandem --- js/src/jit/CodeGenerator.cpp | 4 ++-- js/src/jit/Lowering.cpp | 8 +++++--- js/src/jit/arm/Lowering-arm.h | 3 +++ js/src/jit/arm/MacroAssembler-arm.cpp | 20 +++++--------------- js/src/jit/x64/Lowering-x64.h | 3 +++ js/src/jit/x64/MacroAssembler-x64.cpp | 13 ++++++++----- js/src/jit/x86/Lowering-x86.h | 3 +++ js/src/jit/x86/MacroAssembler-x86.cpp | 14 ++------------ 8 files changed, 31 insertions(+), 37 deletions(-) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 7fe1b0817c05..e3a78c700a1d 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -1831,7 +1831,7 @@ CodeGenerator::visitPostWriteBarrierO(LPostWriteBarrierO *lir) if (!addOutOfLineCode(ool)) return false; - Register temp = ToRegister(lir->temp()); + Register temp = ToTempRegisterOrInvalid(lir->temp()); if (lir->object()->isConstant()) { const Nursery &nursery = GetIonContext()->runtime->gcNursery(); @@ -1855,7 +1855,7 @@ CodeGenerator::visitPostWriteBarrierV(LPostWriteBarrierV *lir) if (!addOutOfLineCode(ool)) return false; - Register temp = ToRegister(lir->temp()); + Register temp = ToTempRegisterOrInvalid(lir->temp()); if (lir->object()->isConstant()) { const Nursery &nursery = GetIonContext()->runtime->gcNursery(); diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index a2ae4d8feaff..91fbfb0378ac 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -2331,15 +2331,17 @@ LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier *ins) #ifdef JSGC_GENERATIONAL switch (ins->value()->type()) { case MIRType_Object: { + LDefinition tmp = needTempForObjectInNurseryRange() ? temp() : LDefinition::BogusTemp(); LPostWriteBarrierO *lir = new(alloc()) LPostWriteBarrierO(useRegisterOrConstant(ins->object()), - useRegister(ins->value()), - temp()); + useRegister(ins->value()), tmp); return add(lir, ins) && assignSafepoint(lir, ins); } case MIRType_Value: { + bool needTemp = needTempForObjectInNurseryRange() || needTempForValueIsNurseryObject(); + LDefinition tmp = needTemp ? temp() : LDefinition::BogusTemp(); LPostWriteBarrierV *lir = - new(alloc()) LPostWriteBarrierV(useRegisterOrConstant(ins->object()), temp()); + new(alloc()) LPostWriteBarrierV(useRegisterOrConstant(ins->object()), tmp); if (!useBox(lir, LPostWriteBarrierV::Input, ins->value())) return false; return add(lir, ins) && assignSafepoint(lir, ins); diff --git a/js/src/jit/arm/Lowering-arm.h b/js/src/jit/arm/Lowering-arm.h index 38a3ff45a1bc..1961858c5ad6 100644 --- a/js/src/jit/arm/Lowering-arm.h +++ b/js/src/jit/arm/Lowering-arm.h @@ -35,6 +35,9 @@ class LIRGeneratorARM : public LIRGeneratorShared return LDefinition::BogusTemp(); } + bool needTempForObjectInNurseryRange() { return false; } + bool needTempForValueIsNurseryObject() { return false; } + // x64 has a scratch register, so no need for another temp for dispatch // ICs. LDefinition tempForDispatchCache(MIRType outputType = MIRType_None) { diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 3634b39739d5..741131289f43 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -4340,12 +4340,12 @@ void MacroAssemblerARMCompat::branchPtrInNurseryRange(Register ptr, Register temp, Label *label) { JS_ASSERT(ptr != temp); - JS_ASSERT(temp != InvalidReg); + JS_ASSERT(ptr != ScratchRegister); const Nursery &nursery = GetIonContext()->runtime->gcNursery(); - movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); - addPtr(ptr, temp); - branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), label); + movePtr(ImmWord(-ptrdiff_t(nursery.start())), ScratchRegister); + addPtr(ptr, ScratchRegister); + branchPtr(Assembler::Below, ScratchRegister, Imm32(Nursery::NurserySize), label); } void @@ -4354,17 +4354,7 @@ MacroAssemblerARMCompat::branchValueIsNurseryObject(ValueOperand value, Register Label done; branchTestObject(Assembler::NotEqual, value, &done); - - Register obj = extractObject(value, temp); - // valobj and temp may be the same register, in which case we mustn't trash it - // before we use its contents. - if (obj == temp) { - const Nursery &nursery = GetIonContext()->runtime->gcNursery(); - addPtr(ImmWord(-ptrdiff_t(nursery.start())), obj); - branchPtr(Assembler::Below, obj, Imm32(Nursery::NurserySize), label); - } else { - branchPtrInNurseryRange(obj, temp, label); - } + branchPtrInNurseryRange(value.payloadReg(), temp, label); bind(&done); } diff --git a/js/src/jit/x64/Lowering-x64.h b/js/src/jit/x64/Lowering-x64.h index 6b58f17d2821..27e5b1374e50 100644 --- a/js/src/jit/x64/Lowering-x64.h +++ b/js/src/jit/x64/Lowering-x64.h @@ -35,6 +35,9 @@ class LIRGeneratorX64 : public LIRGeneratorX86Shared LDefinition tempToUnbox(); + bool needTempForObjectInNurseryRange() { return false; } + bool needTempForValueIsNurseryObject() { return true; } + // x64 has a scratch register, so no need for another temp for dispatch // ICs. LDefinition tempForDispatchCache(MIRType outputType = MIRType_None) { diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp index ccc39b9ea8f2..55dc07106de5 100644 --- a/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -389,23 +389,26 @@ void MacroAssemblerX64::branchPtrInNurseryRange(Register ptr, Register temp, Label *label) { JS_ASSERT(ptr != temp); - JS_ASSERT(temp != InvalidReg); + JS_ASSERT(ptr != ScratchReg); + // temp may be InvalidReg. const Nursery &nursery = GetIonContext()->runtime->gcNursery(); - movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); - addPtr(ptr, temp); - branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), label); + movePtr(ImmWord(-ptrdiff_t(nursery.start())), ScratchReg); + addPtr(ptr, ScratchReg); + branchPtr(Assembler::Below, ScratchReg, Imm32(Nursery::NurserySize), label); } void MacroAssemblerX64::branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label) { + JS_ASSERT(temp != InvalidReg); + Label done; branchTestObject(Assembler::NotEqual, value, &done); Register obj = extractObject(value, temp); - // valobj and temp may be the same register, in which case we mustn't trash it + // obj and temp may be the same register, in which case we mustn't trash it // before we use its contents. if (obj == temp) { const Nursery &nursery = GetIonContext()->runtime->gcNursery(); diff --git a/js/src/jit/x86/Lowering-x86.h b/js/src/jit/x86/Lowering-x86.h index 1590aaab9158..d46050b0af9f 100644 --- a/js/src/jit/x86/Lowering-x86.h +++ b/js/src/jit/x86/Lowering-x86.h @@ -38,6 +38,9 @@ class LIRGeneratorX86 : public LIRGeneratorX86Shared return LDefinition::BogusTemp(); } + bool needTempForObjectInNurseryRange() { return true; } + bool needTempForValueIsNurseryObject() { return true; } + LDefinition tempForDispatchCache(MIRType outputType = MIRType_None); void lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock *block, size_t lirIndex); diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index cfc8147bb367..b366813479ef 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -434,7 +434,7 @@ void MacroAssemblerX86::branchPtrInNurseryRange(Register ptr, Register temp, Label *label) { JS_ASSERT(ptr != temp); - JS_ASSERT(temp != InvalidReg); + JS_ASSERT(temp != InvalidReg); // A temp register is required for x86. const Nursery &nursery = GetIonContext()->runtime->gcNursery(); movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); @@ -448,17 +448,7 @@ MacroAssemblerX86::branchValueIsNurseryObject(ValueOperand value, Register temp, Label done; branchTestObject(Assembler::NotEqual, value, &done); - - Register obj = extractObject(value, temp); - // valobj and temp may be the same register, in which case we mustn't trash it - // before we use its contents. - if (obj == temp) { - const Nursery &nursery = GetIonContext()->runtime->gcNursery(); - addPtr(ImmWord(-ptrdiff_t(nursery.start())), obj); - branchPtr(Assembler::Below, obj, Imm32(Nursery::NurserySize), label); - } else { - branchPtrInNurseryRange(obj, temp, label); - } + branchPtrInNurseryRange(value.payloadReg(), temp, label); bind(&done); } From 4c680c2de855ab69a7761cfb598e94bd2026e868 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 23 Apr 2014 13:48:35 +0100 Subject: [PATCH 22/40] Bug 988950 - Combine value type and nursery check for object r=jandem --- js/src/jit/Lowering.cpp | 5 ++--- js/src/jit/arm/Lowering-arm.h | 3 +-- js/src/jit/x64/Lowering-x64.h | 3 +-- js/src/jit/x64/MacroAssembler-x64.cpp | 24 ++++++------------------ js/src/jit/x86/Lowering-x86.h | 3 +-- 5 files changed, 11 insertions(+), 27 deletions(-) diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 91fbfb0378ac..42ce123d0085 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -2331,15 +2331,14 @@ LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier *ins) #ifdef JSGC_GENERATIONAL switch (ins->value()->type()) { case MIRType_Object: { - LDefinition tmp = needTempForObjectInNurseryRange() ? temp() : LDefinition::BogusTemp(); + LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp(); LPostWriteBarrierO *lir = new(alloc()) LPostWriteBarrierO(useRegisterOrConstant(ins->object()), useRegister(ins->value()), tmp); return add(lir, ins) && assignSafepoint(lir, ins); } case MIRType_Value: { - bool needTemp = needTempForObjectInNurseryRange() || needTempForValueIsNurseryObject(); - LDefinition tmp = needTemp ? temp() : LDefinition::BogusTemp(); + LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp(); LPostWriteBarrierV *lir = new(alloc()) LPostWriteBarrierV(useRegisterOrConstant(ins->object()), tmp); if (!useBox(lir, LPostWriteBarrierV::Input, ins->value())) diff --git a/js/src/jit/arm/Lowering-arm.h b/js/src/jit/arm/Lowering-arm.h index 1961858c5ad6..5bdc9e7c2cbf 100644 --- a/js/src/jit/arm/Lowering-arm.h +++ b/js/src/jit/arm/Lowering-arm.h @@ -35,8 +35,7 @@ class LIRGeneratorARM : public LIRGeneratorShared return LDefinition::BogusTemp(); } - bool needTempForObjectInNurseryRange() { return false; } - bool needTempForValueIsNurseryObject() { return false; } + bool needTempForPostBarrier() { return false; } // x64 has a scratch register, so no need for another temp for dispatch // ICs. diff --git a/js/src/jit/x64/Lowering-x64.h b/js/src/jit/x64/Lowering-x64.h index 27e5b1374e50..e24fae3548e5 100644 --- a/js/src/jit/x64/Lowering-x64.h +++ b/js/src/jit/x64/Lowering-x64.h @@ -35,8 +35,7 @@ class LIRGeneratorX64 : public LIRGeneratorX86Shared LDefinition tempToUnbox(); - bool needTempForObjectInNurseryRange() { return false; } - bool needTempForValueIsNurseryObject() { return true; } + bool needTempForPostBarrier() { return false; } // x64 has a scratch register, so no need for another temp for dispatch // ICs. diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp index 55dc07106de5..449a62e79659 100644 --- a/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -390,7 +390,6 @@ MacroAssemblerX64::branchPtrInNurseryRange(Register ptr, Register temp, Label *l { JS_ASSERT(ptr != temp); JS_ASSERT(ptr != ScratchReg); - // temp may be InvalidReg. const Nursery &nursery = GetIonContext()->runtime->gcNursery(); movePtr(ImmWord(-ptrdiff_t(nursery.start())), ScratchReg); @@ -401,24 +400,13 @@ MacroAssemblerX64::branchPtrInNurseryRange(Register ptr, Register temp, Label *l void MacroAssemblerX64::branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label) { - JS_ASSERT(temp != InvalidReg); + // 'Value' representing the start of the nursery tagged as a JSObject + const Nursery &nursery = GetIonContext()->runtime->gcNursery(); + Value start = ObjectValue(*reinterpret_cast(nursery.start())); - Label done; - - branchTestObject(Assembler::NotEqual, value, &done); - - Register obj = extractObject(value, temp); - // obj and temp may be the same register, in which case we mustn't trash it - // before we use its contents. - if (obj == temp) { - const Nursery &nursery = GetIonContext()->runtime->gcNursery(); - addPtr(ImmWord(-ptrdiff_t(nursery.start())), obj); - branchPtr(Assembler::Below, obj, Imm32(Nursery::NurserySize), label); - } else { - branchPtrInNurseryRange(obj, temp, label); - } - - bind(&done); + movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), ScratchReg); + addPtr(value.valueReg(), ScratchReg); + branchPtr(Assembler::Below, ScratchReg, Imm32(Nursery::NurserySize), label); } #endif diff --git a/js/src/jit/x86/Lowering-x86.h b/js/src/jit/x86/Lowering-x86.h index d46050b0af9f..5b0d4afcb185 100644 --- a/js/src/jit/x86/Lowering-x86.h +++ b/js/src/jit/x86/Lowering-x86.h @@ -38,8 +38,7 @@ class LIRGeneratorX86 : public LIRGeneratorX86Shared return LDefinition::BogusTemp(); } - bool needTempForObjectInNurseryRange() { return true; } - bool needTempForValueIsNurseryObject() { return true; } + bool needTempForPostBarrier() { return true; } LDefinition tempForDispatchCache(MIRType outputType = MIRType_None); From 6eeb144cc5a19f0ae3658a15b6ccc558104fd4c2 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Wed, 23 Apr 2014 08:56:42 -0400 Subject: [PATCH 23/40] Bug 999908 - Remove support for the Web Audio legacy prefs for AudioBufferSourceNode, AudioContext, and AudioParam; r=padenot --- content/media/webaudio/AudioBuffer.cpp | 27 -------- content/media/webaudio/AudioBuffer.h | 2 - .../media/webaudio/AudioBufferSourceNode.h | 15 ----- content/media/webaudio/AudioContext.cpp | 33 ---------- content/media/webaudio/AudioContext.h | 26 -------- content/media/webaudio/AudioParam.h | 4 -- content/media/webaudio/MediaBufferDecoder.cpp | 65 ++----------------- content/media/webaudio/MediaBufferDecoder.h | 3 - content/media/webaudio/test/mochitest.ini | 1 - .../media/webaudio/test/test_AudioParam.html | 36 ---------- .../media/webaudio/test/test_delayNode.html | 10 --- .../media/webaudio/test/test_gainNode.html | 3 - .../webaudio/test/test_mediaDecoding.html | 4 -- .../test/test_scriptProcessorNode.html | 2 +- .../webaudio/test/test_singleSourceDest.html | 59 +++-------------- dom/webidl/AudioBufferSourceNode.webidl | 17 ----- dom/webidl/AudioContext.webidl | 23 ------- dom/webidl/AudioParam.webidl | 11 ---- testing/profiles/prefs_general.js | 3 - 19 files changed, 15 insertions(+), 329 deletions(-) delete mode 100644 content/media/webaudio/test/test_AudioParam.html diff --git a/content/media/webaudio/AudioBuffer.cpp b/content/media/webaudio/AudioBuffer.cpp index 792aa368665b..c926b082f818 100644 --- a/content/media/webaudio/AudioBuffer.cpp +++ b/content/media/webaudio/AudioBuffer.cpp @@ -228,33 +228,6 @@ AudioBuffer::GetThreadSharedChannelsForRate(JSContext* aJSContext) return mSharedChannels; } -void -AudioBuffer::MixToMono(JSContext* aJSContext) -{ - if (mJSChannels.Length() == 1) { - // The buffer is already mono - return; - } - - // Prepare the input channels - nsAutoTArray channels; - channels.SetLength(mJSChannels.Length()); - for (uint32_t i = 0; i < mJSChannels.Length(); ++i) { - channels[i] = JS_GetFloat32ArrayData(mJSChannels[i]); - } - - // Prepare the output channels - float* downmixBuffer = new float[mLength]; - - // Perform the down-mix - AudioChannelsDownMix(channels, &downmixBuffer, 1, mLength); - - // Truncate the shared channels and copy the downmixed data over - mJSChannels.SetLength(1); - SetRawChannelContents(aJSContext, 0, downmixBuffer); - delete[] downmixBuffer; -} - size_t AudioBuffer::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { diff --git a/content/media/webaudio/AudioBuffer.h b/content/media/webaudio/AudioBuffer.h index ed99bae66f70..3d08aa710af8 100644 --- a/content/media/webaudio/AudioBuffer.h +++ b/content/media/webaudio/AudioBuffer.h @@ -101,8 +101,6 @@ public: uint32_t aChannel, float* aContents); - void MixToMono(JSContext* aJSContext); - protected: bool RestoreJSChannelData(JSContext* aJSContext); void ClearJSChannels(); diff --git a/content/media/webaudio/AudioBufferSourceNode.h b/content/media/webaudio/AudioBufferSourceNode.h index 40a8be1a1768..0a118884e949 100644 --- a/content/media/webaudio/AudioBufferSourceNode.h +++ b/content/media/webaudio/AudioBufferSourceNode.h @@ -44,22 +44,7 @@ public: void Start(double aWhen, double aOffset, const Optional& aDuration, ErrorResult& aRv); - void NoteOn(double aWhen, ErrorResult& aRv) - { - Start(aWhen, 0.0, Optional(), aRv); - } - void NoteGrainOn(double aWhen, double aOffset, - double aDuration, ErrorResult& aRv) - { - Optional duration; - duration.Construct(aDuration); - Start(aWhen, aOffset, duration, aRv); - } void Stop(double aWhen, ErrorResult& aRv); - void NoteOff(double aWhen, ErrorResult& aRv) - { - Stop(aWhen, aRv); - } AudioBuffer* GetBuffer(JSContext* aCx) const { diff --git a/content/media/webaudio/AudioContext.cpp b/content/media/webaudio/AudioContext.cpp index 96d775550122..b1b5c69b854f 100644 --- a/content/media/webaudio/AudioContext.cpp +++ b/content/media/webaudio/AudioContext.cpp @@ -204,39 +204,6 @@ AudioContext::CreateBuffer(JSContext* aJSContext, uint32_t aNumberOfChannels, return buffer.forget(); } -already_AddRefed -AudioContext::CreateBuffer(JSContext* aJSContext, const ArrayBuffer& aBuffer, - bool aMixToMono, ErrorResult& aRv) -{ - // Do not accept this method unless the legacy pref has been set. - if (!Preferences::GetBool("media.webaudio.legacy.AudioContext")) { - aRv.ThrowNotEnoughArgsError(); - return nullptr; - } - - // Sniff the content of the media. - // Failed type sniffing will be handled by SyncDecodeMedia. - nsAutoCString contentType; - NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr, - aBuffer.Data(), aBuffer.Length(), - contentType); - - nsRefPtr job = - new WebAudioDecodeJob(contentType, this, aBuffer); - - if (mDecoder.SyncDecodeMedia(contentType.get(), - aBuffer.Data(), aBuffer.Length(), *job) && - job->mOutput) { - nsRefPtr buffer = job->mOutput.forget(); - if (aMixToMono) { - buffer->MixToMono(aJSContext); - } - return buffer.forget(); - } - - return nullptr; -} - namespace { bool IsValidBufferSize(uint32_t aBufferSize) { diff --git a/content/media/webaudio/AudioContext.h b/content/media/webaudio/AudioContext.h index 1bf996450991..1fbeda980e66 100644 --- a/content/media/webaudio/AudioContext.h +++ b/content/media/webaudio/AudioContext.h @@ -126,10 +126,6 @@ public: uint32_t aLength, float aSampleRate, ErrorResult& aRv); - already_AddRefed - CreateBuffer(JSContext* aJSContext, const ArrayBuffer& aBuffer, - bool aMixToMono, ErrorResult& aRv); - already_AddRefed CreateMediaStreamDestination(ErrorResult& aRv); @@ -139,16 +135,6 @@ public: uint32_t aNumberOfOutputChannels, ErrorResult& aRv); - already_AddRefed - CreateJavaScriptNode(uint32_t aBufferSize, - uint32_t aNumberOfInputChannels, - uint32_t aNumberOfOutputChannels, - ErrorResult& aRv) - { - return CreateScriptProcessor(aBufferSize, aNumberOfInputChannels, - aNumberOfOutputChannels, aRv); - } - already_AddRefed CreateAnalyser(); @@ -158,12 +144,6 @@ public: already_AddRefed CreateWaveShaper(); - already_AddRefed - CreateGainNode() - { - return CreateGain(); - } - already_AddRefed CreateMediaElementSource(HTMLMediaElement& aMediaElement, ErrorResult& aRv); already_AddRefed @@ -172,12 +152,6 @@ public: already_AddRefed CreateDelay(double aMaxDelayTime, ErrorResult& aRv); - already_AddRefed - CreateDelayNode(double aMaxDelayTime, ErrorResult& aRv) - { - return CreateDelay(aMaxDelayTime, aRv); - } - already_AddRefed CreatePanner(); diff --git a/content/media/webaudio/AudioParam.h b/content/media/webaudio/AudioParam.h index 51734b1b3f4f..30045251132f 100644 --- a/content/media/webaudio/AudioParam.h +++ b/content/media/webaudio/AudioParam.h @@ -109,10 +109,6 @@ public: AudioParamTimeline::SetTargetAtTime(aTarget, DOMTimeToStreamTime(aStartTime), aTimeConstant, aRv); mCallback(mNode); } - void SetTargetValueAtTime(float aTarget, double aStartTime, double aTimeConstant, ErrorResult& aRv) - { - SetTargetAtTime(aTarget, aStartTime, aTimeConstant, aRv); - } void CancelScheduledValues(double aStartTime, ErrorResult& aRv) { if (!WebAudioUtils::IsTimeValid(aStartTime)) { diff --git a/content/media/webaudio/MediaBufferDecoder.cpp b/content/media/webaudio/MediaBufferDecoder.cpp index d22080974156..578453819e93 100644 --- a/content/media/webaudio/MediaBufferDecoder.cpp +++ b/content/media/webaudio/MediaBufferDecoder.cpp @@ -132,8 +132,6 @@ private: } } - void RunNextPhase(); - void Decode(); void AllocateBuffer(); void CallbackTheResult(); @@ -207,30 +205,6 @@ MediaDecodeTask::CreateReader() return true; } -void -MediaDecodeTask::RunNextPhase() -{ - // This takes care of handling the logic of where to run the next phase. - // If we were invoked synchronously, we do not have a thread pool and - // everything happens on the main thread. Just invoke Run() in that case. - // Otherwise, some things happen on the main thread and others are run - // in the thread pool. - if (!mThreadPool) { - Run(); - return; - } - - switch (mPhase) { - case PhaseEnum::AllocateBuffer: - MOZ_ASSERT(!NS_IsMainThread()); - NS_DispatchToMainThread(this); - break; - case PhaseEnum::Decode: - case PhaseEnum::Done: - MOZ_CRASH("Invalid phase Decode"); - } -} - class AutoResampler { public: AutoResampler() @@ -259,8 +233,7 @@ private: void MediaDecodeTask::Decode() { - MOZ_ASSERT(!mThreadPool == NS_IsMainThread(), - "We should be on the main thread only if we don't have a thread pool"); + MOZ_ASSERT(!NS_IsMainThread()); mBufferDecoder->BeginDecoding(NS_GetCurrentThread()); @@ -395,7 +368,7 @@ MediaDecodeTask::Decode() } mPhase = PhaseEnum::AllocateBuffer; - RunNextPhase(); + NS_DispatchToMainThread(this); } void @@ -489,29 +462,6 @@ MediaBufferDecoder::AsyncDecodeMedia(const char* aContentType, uint8_t* aBuffer, } } -bool -MediaBufferDecoder::SyncDecodeMedia(const char* aContentType, uint8_t* aBuffer, - uint32_t aLength, - WebAudioDecodeJob& aDecodeJob) -{ - // Do not attempt to decode the media if we were not successful at sniffing - // the content type. - if (!*aContentType || - strcmp(aContentType, APPLICATION_OCTET_STREAM) == 0) { - return false; - } - - nsRefPtr task = - new MediaDecodeTask(aContentType, aBuffer, aLength, aDecodeJob, nullptr); - if (!task->CreateReader()) { - return false; - } - - task->Run(); - return true; -} - - bool MediaBufferDecoder::EnsureThreadPoolInitialized() { @@ -536,15 +486,12 @@ WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType, , mFailureCallback(aFailureCallback) { MOZ_ASSERT(aContext); + MOZ_ASSERT(aSuccessCallback); MOZ_ASSERT(NS_IsMainThread()); MOZ_COUNT_CTOR(WebAudioDecodeJob); mArrayBuffer = aBuffer.Obj(); - MOZ_ASSERT(aSuccessCallback || - (!aSuccessCallback && !aFailureCallback), - "If a success callback is not passed, no failure callback should be passed either"); - mozilla::HoldJSObjects(this); } @@ -564,10 +511,8 @@ WebAudioDecodeJob::OnSuccess(ErrorCode aErrorCode) // Ignore errors in calling the callback, since there is not much that we can // do about it here. - if (mSuccessCallback) { - ErrorResult rv; - mSuccessCallback->Call(*mOutput, rv); - } + ErrorResult rv; + mSuccessCallback->Call(*mOutput, rv); mContext->RemoveFromDecodeQueue(this); } diff --git a/content/media/webaudio/MediaBufferDecoder.h b/content/media/webaudio/MediaBufferDecoder.h index f58cc782cd66..7663e393a5b2 100644 --- a/content/media/webaudio/MediaBufferDecoder.h +++ b/content/media/webaudio/MediaBufferDecoder.h @@ -80,9 +80,6 @@ public: void AsyncDecodeMedia(const char* aContentType, uint8_t* aBuffer, uint32_t aLength, WebAudioDecodeJob& aDecodeJob); - bool SyncDecodeMedia(const char* aContentType, uint8_t* aBuffer, - uint32_t aLength, WebAudioDecodeJob& aDecodeJob); - size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { return 0; diff --git a/content/media/webaudio/test/mochitest.ini b/content/media/webaudio/test/mochitest.ini index 9d10879626cc..7b71c2113292 100644 --- a/content/media/webaudio/test/mochitest.ini +++ b/content/media/webaudio/test/mochitest.ini @@ -26,7 +26,6 @@ support-files = [test_AudioBuffer.html] [test_AudioContext.html] [test_AudioListener.html] -[test_AudioParam.html] [test_OfflineAudioContext.html] [test_analyserNode.html] [test_audioBufferSourceNode.html] diff --git a/content/media/webaudio/test/test_AudioParam.html b/content/media/webaudio/test/test_AudioParam.html deleted file mode 100644 index bab8838c1752..000000000000 --- a/content/media/webaudio/test/test_AudioParam.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - Test AudioParam - - - - - -
-
-
- - diff --git a/content/media/webaudio/test/test_delayNode.html b/content/media/webaudio/test/test_delayNode.html index 0baca3338579..a3e314ef79cb 100644 --- a/content/media/webaudio/test/test_delayNode.html +++ b/content/media/webaudio/test/test_delayNode.html @@ -23,9 +23,6 @@ var gTest = { var delay = context.createDelay(); - var delay2 = context.createDelayNode(); - isnot(delay, delay2, "createDelayNode should create a different delay node"); - source.buffer = buffer; source.connect(delay); @@ -40,13 +37,6 @@ var gTest = { is(delay.channelCountMode, "max", "Correct channelCountMode for the delay node"); is(delay.channelInterpretation, "speakers", "Correct channelCountInterpretation for the delay node"); - var delay2 = context.createDelay(2); - is(delay2.delayTime.value, 0, "Correct initial value"); - is(delay2.delayTime.defaultValue, 0, "Correct default value"); - delay2.delayTime.value = 0.5; - is(delay2.delayTime.value, 0.5, "Correct initial value"); - is(delay2.delayTime.defaultValue, 0, "Correct default value"); - expectException(function() { context.createDelay(0); }, DOMException.NOT_SUPPORTED_ERR); diff --git a/content/media/webaudio/test/test_gainNode.html b/content/media/webaudio/test/test_gainNode.html index 4d32ac7d5bbb..41b19fda054d 100644 --- a/content/media/webaudio/test/test_gainNode.html +++ b/content/media/webaudio/test/test_gainNode.html @@ -23,9 +23,6 @@ var gTest = { var gain = context.createGain(); - var gain2 = context.createGainNode(); - isnot(gain, gain2, "createGainNode should create a different gain node"); - source.buffer = buffer; source.connect(gain); diff --git a/content/media/webaudio/test/test_mediaDecoding.html b/content/media/webaudio/test/test_mediaDecoding.html index b4f00144ed04..8d7f49d97ae8 100644 --- a/content/media/webaudio/test/test_mediaDecoding.html +++ b/content/media/webaudio/test/test_mediaDecoding.html @@ -302,8 +302,6 @@ function runResampling(test, response, callback) { var cx = new OfflineAudioContext(1, 1, sampleRate); cx.decodeAudioData(response, function onSuccess(asyncResult) { is(asyncResult.sampleRate, sampleRate, "Correct sample rate"); - syncResult = cx.createBuffer(response, false); - compareBuffers(syncResult, asyncResult); checkResampledBuffer(asyncResult, test, callback); }, function onFailure() { @@ -320,8 +318,6 @@ function runTest(test, response, callback) { ok(expectCallback, "Success callback should fire asynchronously"); ok(test.valid, "Did expect success for test " + test.url); - syncResult = cx.createBuffer(response, false); - compareBuffers(syncResult, asyncResult); checkAudioBuffer(asyncResult, test); test.expectedBuffer = asyncResult; diff --git a/content/media/webaudio/test/test_scriptProcessorNode.html b/content/media/webaudio/test/test_scriptProcessorNode.html index 6982ae36c948..a121812f1cb5 100644 --- a/content/media/webaudio/test/test_scriptProcessorNode.html +++ b/content/media/webaudio/test/test_scriptProcessorNode.html @@ -20,7 +20,7 @@ addLoadEvent(function() { var context = new AudioContext(); var buffer = null; - var sourceSP = context.createJavaScriptNode(2048); + var sourceSP = context.createScriptProcessor(2048); sourceSP.addEventListener("audioprocess", function(e) { // generate the audio for (var i = 0; i < 2048; ++i) { diff --git a/content/media/webaudio/test/test_singleSourceDest.html b/content/media/webaudio/test/test_singleSourceDest.html index 3dda173e2c4d..8613a2dd9d62 100644 --- a/content/media/webaudio/test/test_singleSourceDest.html +++ b/content/media/webaudio/test/test_singleSourceDest.html @@ -28,54 +28,6 @@ addLoadEvent(function() { is(destination.channelInterpretation, "speakers", "Correct channelCountInterpretation for the destination node"); ok(destination instanceof EventTarget, "AudioNodes must be EventTargets"); - testWith(context, buffer, destination, function(source) { - source.start(0); - }, function(source) { - source.stop(); - }, function() { - testWith(context, buffer, destination, function(source) { - source.start(0, 1); - }, function(source) { - expectTypeError(function() { - source.noteOff(); - }); - source.noteOff(0); - }, function() { - testWith(context, buffer, destination, function(source) { - source.start(0, 1, 0.5); - }, function(source) { - source.stop(0); - }, function() { - testWith(context, buffer, destination, function(source) { - source.noteOn(0); - }, function(source) { - source.noteOff(0); - }, function() { - testWith(context, buffer, destination, function(source) { - source.noteGrainOn(0, 1, 0.5); - }, function(source) { - source.stop(); - }, function() { - SimpleTest.finish(); - }); - }); - }); - }); - }); -}); - -function testWith(context, buffer, destination, start, stop, callback) -{ - var source = createNode(context, buffer, destination); - start(source); - SimpleTest.executeSoon(function() { - stop(source); - callback(); - source.disconnect(); - }); -} - -function createNode(context, buffer, destination) { var source = context.createBufferSource(); is(source.context, context, "Source node has proper context"); is(source.numberOfInputs, 0, "Source node has 0 inputs"); @@ -102,8 +54,15 @@ function createNode(context, buffer, destination) { is(destination.numberOfInputs, 1, "Destination node has 0 inputs"); is(destination.numberOfOutputs, 0, "Destination node has 0 outputs"); - return source; -} + source.start(0); + SimpleTest.executeSoon(function() { + source.stop(0); + source.disconnect(); + + SpecialPowers.clearUserPref("media.webaudio.enabled"); + SimpleTest.finish(); + }); +}); diff --git a/dom/webidl/AudioBufferSourceNode.webidl b/dom/webidl/AudioBufferSourceNode.webidl index d38d7266c5aa..bd45d13e16f5 100644 --- a/dom/webidl/AudioBufferSourceNode.webidl +++ b/dom/webidl/AudioBufferSourceNode.webidl @@ -28,20 +28,3 @@ interface AudioBufferSourceNode : AudioNode { attribute EventHandler onended; }; - -/* - * The origin of this IDL file is - * https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#AlternateNames - */ -partial interface AudioBufferSourceNode { - // Same as start() - [Throws,Pref="media.webaudio.legacy.AudioBufferSourceNode"] - void noteOn(double when); - [Throws,Pref="media.webaudio.legacy.AudioBufferSourceNode"] - void noteGrainOn(double when, double grainOffset, double grainDuration); - - [Throws,Pref="media.webaudio.legacy.AudioBufferSourceNode"] - // Same as stop() - void noteOff(double when); -}; - diff --git a/dom/webidl/AudioContext.webidl b/dom/webidl/AudioContext.webidl index aadbd68dee57..304344254029 100644 --- a/dom/webidl/AudioContext.webidl +++ b/dom/webidl/AudioContext.webidl @@ -74,29 +74,6 @@ interface AudioContext : EventTarget { }; -/* - * The origin of this IDL file is - * https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#AlternateNames - */ -partial interface AudioContext { - [NewObject, Throws] - AudioBuffer? createBuffer(ArrayBuffer buffer, boolean mixToMono); - - // Same as createGain() - [NewObject,Pref="media.webaudio.legacy.AudioContext"] - GainNode createGainNode(); - - // Same as createDelay() - [NewObject, Throws, Pref="media.webaudio.legacy.AudioContext"] - DelayNode createDelayNode(optional double maxDelayTime = 1); - - // Same as createScriptProcessor() - [NewObject, Throws, Pref="media.webaudio.legacy.AudioContext"] - ScriptProcessorNode createJavaScriptNode(optional unsigned long bufferSize = 0, - optional unsigned long numberOfInputChannels = 2, - optional unsigned long numberOfOutputChannels = 2); -}; - // Mozilla extensions partial interface AudioContext { // Read AudioChannel.webidl for more information about this attribute. diff --git a/dom/webidl/AudioParam.webidl b/dom/webidl/AudioParam.webidl index 84b18987387e..375ab62791c8 100644 --- a/dom/webidl/AudioParam.webidl +++ b/dom/webidl/AudioParam.webidl @@ -37,14 +37,3 @@ interface AudioParam { void cancelScheduledValues(double startTime); }; - -/* - * The origin of this IDL file is - * https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#AlternateNames - */ -partial interface AudioParam { - // Same as setTargetAtTime() - [Throws,Pref="media.webaudio.legacy.AudioParam"] - void setTargetValueAtTime(float target, double startTime, double timeConstant); -}; - diff --git a/testing/profiles/prefs_general.js b/testing/profiles/prefs_general.js index ffe9d9d88e4e..b816d9d4cd2d 100644 --- a/testing/profiles/prefs_general.js +++ b/testing/profiles/prefs_general.js @@ -144,9 +144,6 @@ user_pref("dom.gamepad.enabled", true); user_pref("dom.gamepad.non_standard_events.enabled", true); // Enable Web Audio legacy APIs -user_pref("media.webaudio.legacy.AudioBufferSourceNode", true); -user_pref("media.webaudio.legacy.AudioContext", true); -user_pref("media.webaudio.legacy.AudioParam", true); user_pref("media.webaudio.legacy.BiquadFilterNode", true); user_pref("media.webaudio.legacy.PannerNode", true); user_pref("media.webaudio.legacy.OscillatorNode", true); From a15a9aedef0b1956d0b2fad3b4de13743b3b98fa Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Wed, 23 Apr 2014 09:26:52 -0400 Subject: [PATCH 24/40] Bug 984460 - Fill in a missing piece of code to compute the right dirty rect in the face of CSS transforms. r=mattwoodrow --- layout/base/nsDisplayList.cpp | 30 ++++++++++++++++++++++++++++++ layout/base/nsDisplayList.h | 6 ++++++ layout/generic/nsFrame.cpp | 18 ++++++------------ 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index ddf2e73e9b20..866b74fbd8f2 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -5098,6 +5098,36 @@ nsRect nsDisplayTransform::TransformRectOut(const nsRect &aUntransformedBounds, factor); } +bool nsDisplayTransform::UntransformRect(const nsRect &aTransformedBounds, + const nsRect &aChildBounds, + const nsIFrame* aFrame, + const nsPoint &aOrigin, + nsRect *aOutRect) +{ + NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!"); + + float factor = aFrame->PresContext()->AppUnitsPerDevPixel(); + + gfx3DMatrix transform = GetResultingTransformMatrix(aFrame, aOrigin, factor, nullptr); + if (transform.IsSingular()) { + return false; + } + + gfxRect result(NSAppUnitsToFloatPixels(aTransformedBounds.x, factor), + NSAppUnitsToFloatPixels(aTransformedBounds.y, factor), + NSAppUnitsToFloatPixels(aTransformedBounds.width, factor), + NSAppUnitsToFloatPixels(aTransformedBounds.height, factor)); + + gfxRect childGfxBounds(NSAppUnitsToFloatPixels(aChildBounds.x, factor), + NSAppUnitsToFloatPixels(aChildBounds.y, factor), + NSAppUnitsToFloatPixels(aChildBounds.width, factor), + NSAppUnitsToFloatPixels(aChildBounds.height, factor)); + + result = transform.UntransformBounds(result, childGfxBounds); + *aOutRect = nsLayoutUtils::RoundGfxRectToAppRect(result, factor); + return true; +} + bool nsDisplayTransform::UntransformVisibleRect(nsDisplayListBuilder* aBuilder, nsRect *aOutRect) { diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 7842d4dbe7f7..6cafad162bdb 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -3258,6 +3258,12 @@ public: /* UntransformRect is like TransformRect, except that it inverts the * transform. */ + static bool UntransformRect(const nsRect &aTransformedBounds, + const nsRect &aChildBounds, + const nsIFrame* aFrame, + const nsPoint &aOrigin, + nsRect *aOutRect); + bool UntransformVisibleRect(nsDisplayListBuilder* aBuilder, nsRect* aOutRect); diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 536921a7776a..269bbe0947e3 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1929,22 +1929,16 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, if (overflow.IsEmpty() && !Preserves3DChildren()) { return; } - // Trying to back-transform arbitrary rects gives us really weird results. I believe - // this is from points that lie beyond the vanishing point. As a workaround we transform - // the overflow rect into screen space and compare in that coordinate system. - // Transform the overflow rect into screen space. nsPoint offset = aBuilder->ToReferenceFrame(this); - nsRect trans = nsDisplayTransform::TransformRect(overflow + offset, this, offset); dirtyRect += offset; - if (dirtyRect.Intersects(trans)) { - // If they intersect, we take our whole overflow rect. We could instead take the intersection - // and then reverse transform it but I doubt this extra work is worthwhile. - dirtyRect = overflow; + + nsRect untransformedDirtyRect; + if (nsDisplayTransform::UntransformRect(dirtyRect, overflow, this, offset, &untransformedDirtyRect)) { + dirtyRect = untransformedDirtyRect; } else { - if (!Preserves3DChildren()) { - return; - } + NS_WARNING("Unable to untransform dirty rect!"); + // This should only happen if the transform is singular, in which case nothing is visible anyway dirtyRect.SetEmpty(); } } From 25b0e226abb0e77cc0ce29edf1d71048da81352a Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Wed, 23 Apr 2014 09:27:58 -0400 Subject: [PATCH 25/40] Bug 993554 - Prevent clipping sync-scrollable subframes to the critical displayport on Fennec. r=BenWa,botond --- gfx/layers/client/ClientTiledThebesLayer.cpp | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/gfx/layers/client/ClientTiledThebesLayer.cpp b/gfx/layers/client/ClientTiledThebesLayer.cpp index 2c0fddadfc10..ddea0badcf9f 100644 --- a/gfx/layers/client/ClientTiledThebesLayer.cpp +++ b/gfx/layers/client/ClientTiledThebesLayer.cpp @@ -86,6 +86,32 @@ ClientTiledThebesLayer::BeginPaint() return; } +#ifdef MOZ_WIDGET_ANDROID + // Subframes on Fennec are not async scrollable because they have no displayport. + // However, the code in RenderLayer() picks up a displayport from the nearest + // scrollable ancestor container layer anyway, which is incorrect for Fennec. This + // behaviour results in the subframe getting clipped improperly and perma-blank areas + // while scrolling the subframe. To work around this, we detect if this layer is + // the primary scrollable layer and disable the tiling behaviour if it is not. + bool isPrimaryScrollableThebesLayer = false; + if (Layer* scrollable = ClientManager()->GetPrimaryScrollableLayer()) { + if (GetParent() == scrollable) { + for (Layer* child = scrollable->GetFirstChild(); child; child = child->GetNextSibling()) { + if (child->GetType() == Layer::TYPE_THEBES) { + if (child == this) { + // |this| is the first thebes layer child of the GetPrimaryScrollableLayer() + isPrimaryScrollableThebesLayer = true; + } + break; + } + } + } + } + if (!isPrimaryScrollableThebesLayer) { + return; + } +#endif + // Get the metrics of the nearest scrollable layer and the nearest layer // with a displayport. ContainerLayer* displayPortParent = nullptr; From 94aaa2a2c1df83bfe8ac7f7349228f7aad071760 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Wed, 23 Apr 2014 09:45:56 -0400 Subject: [PATCH 26/40] Bug 999883 - Make BackgroundHangMonitor not use mozilla::RefCounted; r=froydnj --- xpcom/threads/BackgroundHangMonitor.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/xpcom/threads/BackgroundHangMonitor.cpp b/xpcom/threads/BackgroundHangMonitor.cpp index 694974bf5414..404dcdfb43dd 100644 --- a/xpcom/threads/BackgroundHangMonitor.cpp +++ b/xpcom/threads/BackgroundHangMonitor.cpp @@ -96,14 +96,14 @@ public: * BackgroundHangThread is a per-thread object that is used * by all instances of BackgroundHangMonitor to monitor hangs. */ -class BackgroundHangThread : public RefCounted - , public LinkedListElement +class BackgroundHangThread : public LinkedListElement { private: static ThreadLocal sTlsKey; BackgroundHangThread(const BackgroundHangThread&); BackgroundHangThread& operator=(const BackgroundHangThread&); + ~BackgroundHangThread(); /* Keep a reference to the manager, so we can keep going even after BackgroundHangManager::Shutdown is called. */ @@ -112,7 +112,7 @@ private: const PRThread* mThreadID; public: - MOZ_DECLARE_REFCOUNTED_TYPENAME(BackgroundHangThread) + NS_INLINE_DECL_REFCOUNTING(BackgroundHangThread) static BackgroundHangThread* FindThread(); static void Startup() @@ -144,7 +144,6 @@ public: BackgroundHangThread(const char* aName, uint32_t aTimeoutMs, uint32_t aMaxTimeoutMs); - ~BackgroundHangThread(); // Report a hang; aManager->mLock IS locked void ReportHang(PRIntervalTime aHangTime); From 8d457861b881893d3fa3493b8f1dbab1e9ef82a6 Mon Sep 17 00:00:00 2001 From: Maksim Lebedev Date: Wed, 23 Apr 2014 09:56:46 -0400 Subject: [PATCH 27/40] Bug 979345 - Implement "touch-action: manipulation" CSS value for Pointer Events. r=kats,botond,dbaron,mbrubeck --- gfx/layers/apz/src/APZCTreeManager.h | 5 ++-- gfx/layers/apz/src/AsyncPanZoomController.cpp | 26 +++++++++++++------ gfx/layers/apz/src/AsyncPanZoomController.h | 9 +++++-- .../gtest/TestAsyncPanZoomController.cpp | 6 ++--- layout/style/nsCSSKeywordList.h | 1 + layout/style/nsCSSParser.cpp | 13 ++++++++-- layout/style/nsCSSProps.cpp | 9 ++++--- layout/style/nsCSSValue.cpp | 4 +-- layout/style/nsComputedDOMStyle.cpp | 22 ++++++---------- layout/style/nsStyleConsts.h | 1 + layout/style/test/property_database.js | 13 +++++++--- widget/xpwidgets/ContentHelper.cpp | 13 ++++++---- 12 files changed, 78 insertions(+), 44 deletions(-) diff --git a/gfx/layers/apz/src/APZCTreeManager.h b/gfx/layers/apz/src/APZCTreeManager.h index 5d3e2e12f437..b0eec16712ac 100644 --- a/gfx/layers/apz/src/APZCTreeManager.h +++ b/gfx/layers/apz/src/APZCTreeManager.h @@ -32,8 +32,9 @@ enum AllowedTouchBehavior { NONE = 0, VERTICAL_PAN = 1 << 0, HORIZONTAL_PAN = 1 << 1, - ZOOM = 1 << 2, - UNKNOWN = 1 << 3 + PINCH_ZOOM = 1 << 2, + DOUBLE_TAP_ZOOM = 1 << 3, + UNKNOWN = 1 << 4 }; class Layer; diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp index c8af51ad5ded..c09e5aee3176 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -233,7 +233,8 @@ typedef GeckoContentController::APZStateChange APZStateChange; */ static const uint32_t DefaultTouchBehavior = AllowedTouchBehavior::VERTICAL_PAN | AllowedTouchBehavior::HORIZONTAL_PAN | - AllowedTouchBehavior::ZOOM; + AllowedTouchBehavior::PINCH_ZOOM | + AllowedTouchBehavior::DOUBLE_TAP_ZOOM; /** * Angle from axis within which we stay axis-locked @@ -781,7 +782,7 @@ nsEventStatus AsyncPanZoomController::OnTouchCancel(const MultiTouchInput& aEven nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEvent) { APZC_LOG("%p got a scale-begin in state %d\n", this, mState); - if (!TouchActionAllowZoom()) { + if (!TouchActionAllowPinchZoom()) { return nsEventStatus_eIgnore; } @@ -972,7 +973,7 @@ nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEven APZC_LOG("%p got a single-tap-up in state %d\n", this, mState); // If mZoomConstraints.mAllowDoubleTapZoom is true we wait for a call to OnSingleTapConfirmed before // sending event to content - if (!mZoomConstraints.mAllowDoubleTapZoom) { + if (!(mZoomConstraints.mAllowDoubleTapZoom && TouchActionAllowDoubleTapZoom())) { return GenerateSingleTap(aEvent.mPoint, aEvent.modifiers); } return nsEventStatus_eIgnore; @@ -987,14 +988,13 @@ nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent) APZC_LOG("%p got a double-tap in state %d\n", this, mState); nsRefPtr controller = GetGeckoContentController(); if (controller) { - if (mZoomConstraints.mAllowDoubleTapZoom) { + if (mZoomConstraints.mAllowDoubleTapZoom && TouchActionAllowDoubleTapZoom()) { int32_t modifiers = WidgetModifiersToDOMModifiers(aEvent.modifiers); CSSPoint geckoScreenPoint; if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) { controller->HandleDoubleTap(geckoScreenPoint, modifiers, GetGuid()); } } - return nsEventStatus_eConsumeNoDefault; } return nsEventStatus_eIgnore; @@ -1961,19 +1961,29 @@ void AsyncPanZoomController::CheckContentResponse() { } } -bool AsyncPanZoomController::TouchActionAllowZoom() { +bool AsyncPanZoomController::TouchActionAllowPinchZoom() { if (!mTouchActionPropertyEnabled) { return true; } - // Pointer events specification implies all touch points to allow zoom // to perform it. for (size_t i = 0; i < mTouchBlockState.mAllowedTouchBehaviors.Length(); i++) { - if (!(mTouchBlockState.mAllowedTouchBehaviors[i] & AllowedTouchBehavior::ZOOM)) { + if (!(mTouchBlockState.mAllowedTouchBehaviors[i] & AllowedTouchBehavior::PINCH_ZOOM)) { return false; } } + return true; +} +bool AsyncPanZoomController::TouchActionAllowDoubleTapZoom() { + if (!mTouchActionPropertyEnabled) { + return true; + } + for (size_t i = 0; i < mTouchBlockState.mAllowedTouchBehaviors.Length(); i++) { + if (!(mTouchBlockState.mAllowedTouchBehaviors[i] & AllowedTouchBehavior::DOUBLE_TAP_ZOOM)) { + return false; + } + } return true; } diff --git a/gfx/layers/apz/src/AsyncPanZoomController.h b/gfx/layers/apz/src/AsyncPanZoomController.h index 996f8abd700f..3c67ba157da5 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.h +++ b/gfx/layers/apz/src/AsyncPanZoomController.h @@ -595,9 +595,14 @@ private: }; /* - * Returns whether current touch behavior values allow zooming. + * Returns whether current touch behavior values allow pinch-zooming. */ - bool TouchActionAllowZoom(); + bool TouchActionAllowPinchZoom(); + + /* + * Returns whether current touch behavior values allow double-tap-zooming. + */ + bool TouchActionAllowDoubleTapZoom(); /* * Returns allowed touch behavior from the mAllowedTouchBehavior array. diff --git a/gfx/tests/gtest/TestAsyncPanZoomController.cpp b/gfx/tests/gtest/TestAsyncPanZoomController.cpp index 07e0d6ad00c9..cbe592927cff 100644 --- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp +++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp @@ -415,7 +415,7 @@ TEST_F(AsyncPanZoomControllerTester, PinchWithTouchActionNone) { nsTArray values; values.AppendElement(mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN); - values.AppendElement(mozilla::layers::AllowedTouchBehavior::ZOOM); + values.AppendElement(mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM); apzc->SetTouchActionEnabled(true); apzc->SetAllowedTouchBehavior(values); @@ -906,7 +906,7 @@ TEST_F(AsyncPanZoomControllerTester, LongPress) { TEST_F(AsyncPanZoomControllerTester, LongPressWithTouchAction) { DoLongPressTest(true, mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN | mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN - | mozilla::layers::AllowedTouchBehavior::ZOOM); + | mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM); } TEST_F(AsyncPanZoomControllerTester, LongPressPreventDefault) { @@ -916,7 +916,7 @@ TEST_F(AsyncPanZoomControllerTester, LongPressPreventDefault) { TEST_F(AsyncPanZoomControllerTester, LongPressPreventDefaultWithTouchAction) { DoLongPressPreventDefaultTest(true, mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN | mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN - | mozilla::layers::AllowedTouchBehavior::ZOOM); + | mozilla::layers::AllowedTouchBehavior::PINCH_ZOOM); } // Layer tree for HitTesting1 diff --git a/layout/style/nsCSSKeywordList.h b/layout/style/nsCSSKeywordList.h index 606023d9b5ae..c43eaa990b37 100644 --- a/layout/style/nsCSSKeywordList.h +++ b/layout/style/nsCSSKeywordList.h @@ -372,6 +372,7 @@ CSS_KEY(lowercase, lowercase) CSS_KEY(ltr, ltr) CSS_KEY(luminance, luminance) CSS_KEY(luminosity, luminosity) +CSS_KEY(manipulation, manipulation) CSS_KEY(manual, manual) CSS_KEY(margin-box, margin_box) CSS_KEY(markers, markers) diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index 9a7aff43e95a..e0e749d479d6 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -12405,8 +12405,10 @@ CSSParserImpl::ParseTextOverflow(nsCSSValue& aValue) bool CSSParserImpl::ParseTouchAction(nsCSSValue& aValue) { - if (!ParseVariant(aValue, VARIANT_HK | VARIANT_NONE | VARIANT_AUTO, - nsCSSProps::kTouchActionKTable)) { + // Avaliable values of property touch-action: + // auto | none | [pan-x || pan-y] | manipulation + + if (!ParseVariant(aValue, VARIANT_HK, nsCSSProps::kTouchActionKTable)) { return false; } @@ -12426,6 +12428,13 @@ CSSParserImpl::ParseTouchAction(nsCSSValue& aValue) return false; } + // Auto and None and Manipulation is not allowed in conjunction with others. + if ((intValue | nextIntValue) & (NS_STYLE_TOUCH_ACTION_NONE | + NS_STYLE_TOUCH_ACTION_AUTO | + NS_STYLE_TOUCH_ACTION_MANIPULATION)) { + return false; + } + aValue.SetIntValue(nextIntValue | intValue, eCSSUnit_Enumerated); } diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp index 886407141b64..80803f987c79 100644 --- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -1620,9 +1620,12 @@ const KTableValue nsCSSProps::kTextTransformKTable[] = { }; const KTableValue nsCSSProps::kTouchActionKTable[] = { - eCSSKeyword_pan_x, NS_STYLE_TOUCH_ACTION_PAN_X, - eCSSKeyword_pan_y, NS_STYLE_TOUCH_ACTION_PAN_Y, - eCSSKeyword_UNKNOWN, -1 + eCSSKeyword_none, NS_STYLE_TOUCH_ACTION_NONE, + eCSSKeyword_auto, NS_STYLE_TOUCH_ACTION_AUTO, + eCSSKeyword_pan_x, NS_STYLE_TOUCH_ACTION_PAN_X, + eCSSKeyword_pan_y, NS_STYLE_TOUCH_ACTION_PAN_Y, + eCSSKeyword_manipulation, NS_STYLE_TOUCH_ACTION_MANIPULATION, + eCSSKeyword_UNKNOWN, -1 }; const KTableValue nsCSSProps::kTransitionTimingFunctionKTable[] = { diff --git a/layout/style/nsCSSValue.cpp b/layout/style/nsCSSValue.cpp index e0a720328344..781ef65c8bfd 100644 --- a/layout/style/nsCSSValue.cpp +++ b/layout/style/nsCSSValue.cpp @@ -1048,8 +1048,8 @@ nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult, case eCSSProperty_touch_action: nsStyleUtil::AppendBitmaskCSSValue(aProperty, intValue, - NS_STYLE_TOUCH_ACTION_PAN_X, - NS_STYLE_TOUCH_ACTION_PAN_Y, + NS_STYLE_TOUCH_ACTION_NONE, + NS_STYLE_TOUCH_ACTION_MANIPULATION, aResult); break; diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index dcf90381c5e0..1f6993492fcd 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -4063,20 +4063,14 @@ nsComputedDOMStyle::DoGetTouchAction() int32_t intValue = StyleDisplay()->mTouchAction; - // None and Auto values aren't allowed to be in conjunction with - // other values. - if (NS_STYLE_TOUCH_ACTION_AUTO == intValue) { - val->SetIdent(eCSSKeyword_auto); - } else if (NS_STYLE_TOUCH_ACTION_NONE == intValue) { - val->SetIdent(eCSSKeyword_none); - } else { - nsAutoString valueStr; - nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_touch_action, - intValue, NS_STYLE_TOUCH_ACTION_PAN_X, - NS_STYLE_TOUCH_ACTION_PAN_Y, valueStr); - val->SetString(valueStr); - } - + // None and Auto and Manipulation values aren't allowed + // to be in conjunction with other values. + // But there are all checks in CSSParserImpl::ParseTouchAction + nsAutoString valueStr; + nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_touch_action, intValue, + NS_STYLE_TOUCH_ACTION_NONE, NS_STYLE_TOUCH_ACTION_MANIPULATION, + valueStr); + val->SetString(valueStr); return val; } diff --git a/layout/style/nsStyleConsts.h b/layout/style/nsStyleConsts.h index e2de9998afea..8836c798532a 100644 --- a/layout/style/nsStyleConsts.h +++ b/layout/style/nsStyleConsts.h @@ -779,6 +779,7 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) { #define NS_STYLE_TOUCH_ACTION_AUTO (1 << 1) #define NS_STYLE_TOUCH_ACTION_PAN_X (1 << 2) #define NS_STYLE_TOUCH_ACTION_PAN_Y (1 << 3) +#define NS_STYLE_TOUCH_ACTION_MANIPULATION (1 << 4) // See nsStyleDisplay #define NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE 0 diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index b5ba594a87f1..ac6dbf3eb2f3 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -4373,10 +4373,17 @@ if (SpecialPowers.getBoolPref("layout.css.touch_action.enabled")) { inherited: false, type: CSS_TYPE_LONGHAND, initial_values: ["auto"], - other_values: ["none", "pan-x", "pan-y", "pan-x pan-y", "pan-y pan-x"], + other_values: ["none", "pan-x", "pan-y", "pan-x pan-y", "pan-y pan-x", "manipulation"], invalid_values: ["zoom", "pinch", "tap", "10px", "2", "auto pan-x", "pan-x auto", "none pan-x", "pan-x none", - "auto pan-y", "pan-y auto", "none pan-y", "pan-y none", - "pan-x pan-y none", "none pan-x pan-y", "pan-x pan-y auto", "auto pan-x pan-y"] + "auto pan-y", "pan-y auto", "none pan-y", "pan-y none", "pan-x pan-x", "pan-y pan-y", + "pan-x pan-y none", "pan-x none pan-y", "none pan-x pan-y", "pan-y pan-x none", "pan-y none pan-x", "none pan-y pan-x", + "pan-x pan-y auto", "pan-x auto pan-y", "auto pan-x pan-y", "pan-y pan-x auto", "pan-y auto pan-x", "auto pan-y pan-x", + "pan-x pan-y zoom", "pan-x zoom pan-y", "zoom pan-x pan-y", "pan-y pan-x zoom", "pan-y zoom pan-x", "zoom pan-y pan-x", + "pan-x pan-y pan-x", "pan-x pan-x pan-y", "pan-y pan-x pan-x", "pan-y pan-x pan-y", "pan-y pan-y pan-x", "pan-x pan-y pan-y", + "manipulation none", "none manipulation", "manipulation auto", "auto manipulation", "manipulation zoom", "zoom manipulation", + "manipulation manipulation", "manipulation pan-x", "pan-x manipulation", "manipulation pan-y", "pan-y manipulation", + "manipulation pan-x pan-y", "pan-x manipulation pan-y", "pan-x pan-y manipulation", + "manipulation pan-y pan-x", "pan-y manipulation pan-x", "pan-y pan-x manipulation"] }; } diff --git a/widget/xpwidgets/ContentHelper.cpp b/widget/xpwidgets/ContentHelper.cpp index f7c6698a2802..a85258ee2e0e 100644 --- a/widget/xpwidgets/ContentHelper.cpp +++ b/widget/xpwidgets/ContentHelper.cpp @@ -35,9 +35,12 @@ void ContentHelper::UpdateAllowedBehavior(uint32_t aTouchActionValue, bool aConsiderPanning, TouchBehaviorFlags& aOutBehavior) { if (aTouchActionValue != NS_STYLE_TOUCH_ACTION_AUTO) { - // Dropping zoom flag since zooming requires touch-action values of all touches - // to be AUTO. - aOutBehavior &= ~AllowedTouchBehavior::ZOOM; + // Double-tap-zooming need property value AUTO + aOutBehavior &= ~AllowedTouchBehavior::DOUBLE_TAP_ZOOM; + if (aTouchActionValue != NS_STYLE_TOUCH_ACTION_MANIPULATION) { + // Pinch-zooming need value AUTO or MANIPULATION + aOutBehavior &= ~AllowedTouchBehavior::PINCH_ZOOM; + } } if (aConsiderPanning) { @@ -86,7 +89,7 @@ ContentHelper::GetAllowedTouchBehavior(nsIWidget* aWidget, const nsIntPoint& aPo bool considerPanning = true; TouchBehaviorFlags behavior = AllowedTouchBehavior::VERTICAL_PAN | AllowedTouchBehavior::HORIZONTAL_PAN | - AllowedTouchBehavior::ZOOM; + AllowedTouchBehavior::PINCH_ZOOM | AllowedTouchBehavior::DOUBLE_TAP_ZOOM; for (nsIFrame *frame = target; frame && frame->GetContent() && behavior; frame = frame->GetParent()) { UpdateAllowedBehavior(GetTouchActionFromFrame(frame), considerPanning, behavior); @@ -102,4 +105,4 @@ ContentHelper::GetAllowedTouchBehavior(nsIWidget* aWidget, const nsIntPoint& aPo } } -} \ No newline at end of file +} From 94bbbf60fdbbd0d50813a16668c3b61f8ac46839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Wang?= Date: Wed, 23 Apr 2014 06:57:41 -0700 Subject: [PATCH 28/40] Bug 407059 - Part 0: Remove the Truncate() calls from nsMathMLChar::StretchEnumContext. r=karlt --- layout/mathml/nsMathMLChar.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp index ce80c10c8ee1..606b649851e2 100644 --- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -963,8 +963,6 @@ nsMathMLChar::StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable, // Use our stretchy style context now that stretching is in progress nsStyleContext *sc = mChar->mStyleContext; nsFont font = sc->StyleFont()->mFont; - // Ensure SetFontFamily will set the font - font.name.Truncate(); bool isVertical = (mDirection == NS_STRETCH_DIRECTION_VERTICAL); bool largeop = (NS_STRETCH_LARGEOP & mStretchHint) != 0; @@ -1064,8 +1062,6 @@ nsMathMLChar::StretchEnumContext::TryParts(nsGlyphTable* aGlyphTable, // Use our stretchy style context now that stretching is in progress nsFont font = mChar->mStyleContext->StyleFont()->mFont; - // Ensure SetFontFamily will set the font - font.name.Truncate(); // Compute the bounding metrics of all partial glyphs nsAutoPtr textRun[4]; From e9daefe35d20b8c7b8462c6eb6f94a9d77aabcde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Wang?= Date: Wed, 23 Apr 2014 06:57:42 -0700 Subject: [PATCH 29/40] Bug 407059 - Part 1: Add a gfxMathTable class to read the MATH table. r=jfkthame --- gfx/thebes/MathTableStructures.h | 121 ++++++++ gfx/thebes/gfxFont.cpp | 75 +++++ gfx/thebes/gfxFont.h | 76 +++++ gfx/thebes/gfxMathTable.cpp | 459 +++++++++++++++++++++++++++++++ gfx/thebes/gfxMathTable.h | 122 ++++++++ gfx/thebes/moz.build | 2 + 6 files changed, 855 insertions(+) create mode 100644 gfx/thebes/MathTableStructures.h create mode 100644 gfx/thebes/gfxMathTable.cpp create mode 100644 gfx/thebes/gfxMathTable.h diff --git a/gfx/thebes/MathTableStructures.h b/gfx/thebes/MathTableStructures.h new file mode 100644 index 000000000000..69a70cb8d167 --- /dev/null +++ b/gfx/thebes/MathTableStructures.h @@ -0,0 +1,121 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This file contains the structures described in Microsoft's document +// "The MATH table and OpenType Features for Math Processing" (not yet public). +// +// Arrays of varying size are indicated in comments. Typically, gfxMathTable +// will read the header of the structure first, verify that there is enough +// space for the specified arrays and then use a pointer to browse these arrays. + +#ifndef MATH_TABLE_STRUCTURE_H +#define MATH_TABLE_STRUCTURE_H + +#include "gfxFontUtils.h" + +typedef mozilla::AutoSwap_PRUint16 Count16; +typedef mozilla::AutoSwap_PRUint16 GlyphID; +typedef mozilla::AutoSwap_PRUint16 Offset; + +struct MathValueRecord { + mozilla::AutoSwap_PRInt16 mValue; + Offset mDeviceTable; +}; + +struct RangeRecord { + GlyphID mStart; + GlyphID mEnd; + mozilla::AutoSwap_PRUint16 mStartCoverageIndex; +}; + +struct Coverage { + mozilla::AutoSwap_PRUint16 mFormat; +}; + +struct CoverageFormat1 { + mozilla::AutoSwap_PRUint16 mFormat; + Count16 mGlyphCount; + // GlyphID mGlyphArray[mGlyphCount] +}; + +struct CoverageFormat2 { + mozilla::AutoSwap_PRUint16 mFormat; + Count16 mRangeCount; + // RangeRecord mRangeArray[mRangeCount]; +}; + +struct MATHTableHeader { + mozilla::AutoSwap_PRUint32 mVersion; + Offset mMathConstants; + Offset mMathGlyphInfo; + Offset mMathVariants; +}; + +struct MathConstants { + mozilla::AutoSwap_PRInt16 mInt16[gfxFontEntry::ScriptScriptPercentScaleDown - + gfxFontEntry::ScriptPercentScaleDown + 1]; + mozilla::AutoSwap_PRUint16 mUint16[gfxFontEntry::DisplayOperatorMinHeight - + gfxFontEntry:: + DelimitedSubFormulaMinHeight + 1]; + MathValueRecord mMathValues[gfxFontEntry::RadicalKernAfterDegree - + gfxFontEntry::MathLeading + 1]; + mozilla::AutoSwap_PRUint16 mRadicalDegreeBottomRaisePercent; +}; + +struct MathGlyphInfo { + Offset mMathItalicsCorrectionInfo; + Offset mMathTopAccentAttachment; + Offset mExtendedShapeCoverage; + Offset mMathKernInfo; +}; + +struct MathItalicsCorrectionInfo { + Offset mCoverage; + Count16 mItalicsCorrectionCount; + // MathValueRecord mItalicsCorrection[mItalicsCorrectionCount] +}; + +struct MathVariants { + mozilla::AutoSwap_PRUint16 mMinConnectorOverlap; + Offset mVertGlyphCoverage; + Offset mHorizGlyphCoverage; + Count16 mVertGlyphCount; + Count16 mHorizGlyphCount; + // Offset mVertGlyphConstruction[mVertGlyphCount]; + // Offset mHorizGlyphConstruction[mHorizGlyphCount]; +}; + +struct MathGlyphVariantRecord { + GlyphID mVariantGlyph; + mozilla::AutoSwap_PRUint16 mAdvanceMeasurement; +}; + +struct MathGlyphConstruction { + Offset mGlyphAssembly; + Count16 mVariantCount; + // MathGlyphVariantRecord mMathGlyphVariantRecord[mVariantCount] +}; + +struct GlyphPartRecord { + GlyphID mGlyph; + mozilla::AutoSwap_PRUint16 mStartConnectorLength; + mozilla::AutoSwap_PRUint16 mEndConnectorLength; + mozilla::AutoSwap_PRUint16 mFullAdvance; + mozilla::AutoSwap_PRUint16 mPartFlags; +}; + +// PartFlags enumeration currently uses only one bit: +// 0x0001 If set, the part can be skipped or repeated. +// 0xFFFE Reserved. +enum { + PART_FLAG_EXTENDER = 0x01 +}; + +struct GlyphAssembly { + MathValueRecord mItalicsCorrection; + Count16 mPartCount; + // GlyphPartRecord mPartRecords[mPartCount] +}; + +#endif diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 1157f4f8056b..c0aa3bb9c8c4 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -38,6 +38,7 @@ #include "mozilla/Services.h" #include "mozilla/Telemetry.h" #include "gfxSVGGlyphs.h" +#include "gfxMathTable.h" #include "gfx2DGlue.h" #if defined(XP_MACOSX) @@ -112,6 +113,7 @@ gfxFontEntry::gfxFontEntry() : mIgnoreGDEF(false), mIgnoreGSUB(false), mSVGInitialized(false), + mMathInitialized(false), mHasSpaceFeaturesInitialized(false), mHasSpaceFeatures(false), mHasSpaceFeaturesKerning(false), @@ -141,6 +143,7 @@ gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) : mIgnoreGDEF(false), mIgnoreGSUB(false), mSVGInitialized(false), + mMathInitialized(false), mHasSpaceFeaturesInitialized(false), mHasSpaceFeatures(false), mHasSpaceFeaturesKerning(false), @@ -389,6 +392,78 @@ gfxFontEntry::NotifyGlyphsChanged() } } +bool +gfxFontEntry::TryGetMathTable(gfxFont* aFont) +{ + if (!mMathInitialized) { + mMathInitialized = true; + + // If UnitsPerEm is not known/valid, we can't use MATH table + if (UnitsPerEm() == kInvalidUPEM) { + return false; + } + + // We don't use AutoTable here because we'll pass ownership of this + // blob to the gfxMathTable, once we've confirmed the table exists + hb_blob_t *mathTable = GetFontTable(TRUETYPE_TAG('M','A','T','H')); + if (!mathTable) { + return false; + } + + // gfxMathTable will hb_blob_destroy() the table when it is finished + // with it. + mMathTable = new gfxMathTable(mathTable); + if (!mMathTable->HasValidHeaders()) { + mMathTable = nullptr; + return false; + } + } + + return !!mMathTable; +} + +gfxFloat +gfxFontEntry::GetMathConstant(gfxFontEntry::MathConstant aConstant) +{ + NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first."); + gfxFloat value = mMathTable->GetMathConstant(aConstant); + if (aConstant == gfxFontEntry::ScriptPercentScaleDown || + aConstant == gfxFontEntry::ScriptScriptPercentScaleDown || + aConstant == gfxFontEntry::RadicalDegreeBottomRaisePercent) { + return value / 100.0; + } + return value / mUnitsPerEm; +} + +bool +gfxFontEntry::GetMathItalicsCorrection(uint32_t aGlyphID, + gfxFloat* aItalicCorrection) +{ + NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first."); + int16_t italicCorrection; + if (!mMathTable->GetMathItalicsCorrection(aGlyphID, &italicCorrection)) { + return false; + } + *aItalicCorrection = gfxFloat(italicCorrection) / mUnitsPerEm; + return true; +} + +uint32_t +gfxFontEntry::GetMathVariantsSize(uint32_t aGlyphID, bool aVertical, + uint16_t aSize) +{ + NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first."); + return mMathTable->GetMathVariantsSize(aGlyphID, aVertical, aSize); +} + +bool +gfxFontEntry::GetMathVariantsParts(uint32_t aGlyphID, bool aVertical, + uint32_t aGlyphs[4]) +{ + NS_ASSERTION(mMathTable, "Math data has not yet been loaded. TryGetMathData() first."); + return mMathTable->GetMathVariantsParts(aGlyphID, aVertical, aGlyphs); +} + /** * FontTableBlobData * diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index aadfc638075e..ac0443178cec 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -48,6 +48,7 @@ class gfxUserFontData; class gfxShapedText; class gfxShapedWord; class gfxSVGGlyphs; +class gfxMathTable; class gfxTextContextPaint; class FontInfoData; @@ -311,6 +312,79 @@ public: // (e.g. animated SVG glyphs) void NotifyGlyphsChanged(); + enum MathConstant { + // The order of the constants must match the order of the fields + // defined in the MATH table. + ScriptPercentScaleDown, + ScriptScriptPercentScaleDown, + DelimitedSubFormulaMinHeight, + DisplayOperatorMinHeight, + MathLeading, + AxisHeight, + AccentBaseHeight, + FlattenedAccentBaseHeight, + SubscriptShiftDown, + SubscriptTopMax, + SubscriptBaselineDropMin, + SuperscriptShiftUp, + SuperscriptShiftUpCramped, + SuperscriptBottomMin, + SuperscriptBaselineDropMax, + SubSuperscriptGapMin, + SuperscriptBottomMaxWithSubscript, + SpaceAfterScript, + UpperLimitGapMin, + UpperLimitBaselineRiseMin, + LowerLimitGapMin, + LowerLimitBaselineDropMin, + StackTopShiftUp, + StackTopDisplayStyleShiftUp, + StackBottomShiftDown, + StackBottomDisplayStyleShiftDown, + StackGapMin, + StackDisplayStyleGapMin, + StretchStackTopShiftUp, + StretchStackBottomShiftDown, + StretchStackGapAboveMin, + StretchStackGapBelowMin, + FractionNumeratorShiftUp, + FractionNumeratorDisplayStyleShiftUp, + FractionDenominatorShiftDown, + FractionDenominatorDisplayStyleShiftDown, + FractionNumeratorGapMin, + FractionNumDisplayStyleGapMin, + FractionRuleThickness, + FractionDenominatorGapMin, + FractionDenomDisplayStyleGapMin, + SkewedFractionHorizontalGap, + SkewedFractionVerticalGap, + OverbarVerticalGap, + OverbarRuleThickness, + OverbarExtraAscender, + UnderbarVerticalGap, + UnderbarRuleThickness, + UnderbarExtraDescender, + RadicalVerticalGap, + RadicalDisplayStyleVerticalGap, + RadicalRuleThickness, + RadicalExtraAscender, + RadicalKernBeforeDegree, + RadicalKernAfterDegree, + RadicalDegreeBottomRaisePercent + }; + + // Call TryGetMathTable to try to load the Open Type MATH table. The other + // functions forward the call to the gfxMathTable class. The GetMath...() + // functions MUST NOT be called unless TryGetMathTable() has returned true. + bool TryGetMathTable(gfxFont* aFont); + gfxFloat GetMathConstant(MathConstant aConstant); + bool GetMathItalicsCorrection(uint32_t aGlyphID, + gfxFloat* aItalicCorrection); + uint32_t GetMathVariantsSize(uint32_t aGlyphID, bool aVertical, + uint16_t aSize); + bool GetMathVariantsParts(uint32_t aGlyphID, bool aVertical, + uint32_t aGlyphs[4]); + virtual bool MatchesGenericFamily(const nsACString& aGeneric) const { return true; } @@ -433,6 +507,7 @@ public: bool mIgnoreGDEF : 1; bool mIgnoreGSUB : 1; bool mSVGInitialized : 1; + bool mMathInitialized : 1; bool mHasSpaceFeaturesInitialized : 1; bool mHasSpaceFeatures : 1; bool mHasSpaceFeaturesKerning : 1; @@ -458,6 +533,7 @@ public: nsAutoPtr mSVGGlyphs; // list of gfxFonts that are using SVG glyphs nsTArray mFontsUsingSVGGlyphs; + nsAutoPtr mMathTable; nsTArray mFeatureSettings; uint32_t mLanguageOverride; diff --git a/gfx/thebes/gfxMathTable.cpp b/gfx/thebes/gfxMathTable.cpp new file mode 100644 index 000000000000..bf5daf1b3001 --- /dev/null +++ b/gfx/thebes/gfxMathTable.cpp @@ -0,0 +1,459 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gfxMathTable.h" + +#include "MathTableStructures.h" +#include "harfbuzz/hb.h" +#include + +using namespace mozilla; + +gfxMathTable::gfxMathTable(hb_blob_t* aMathTable) + : mMathTable(aMathTable) + , mGlyphConstruction(nullptr) + , mGlyphID(-1) + , mVertical(false) +{ +} + +gfxMathTable::~gfxMathTable() +{ + hb_blob_destroy(mMathTable); +} + +bool +gfxMathTable::HasValidHeaders() +{ + const char* mathData = hb_blob_get_data(mMathTable, nullptr); + // Verify the MATH table header. + if (!ValidStructure(mathData, sizeof(MATHTableHeader))) { + return false; + } + const MATHTableHeader* header = GetMATHTableHeader(); + if (uint32_t(header->mVersion) != 0x00010000 || + !ValidOffset(mathData, uint16_t(header->mMathConstants)) || + !ValidOffset(mathData, uint16_t(header->mMathGlyphInfo)) || + !ValidOffset(mathData, uint16_t(header->mMathVariants))) { + return false; + } + + // Verify the MathConstants header. + const MathConstants* mathconstants = GetMathConstants(); + const char* start = reinterpret_cast(mathconstants); + if (!ValidStructure(start, sizeof(MathConstants))) { + return false; + } + + // Verify the MathGlyphInfo header. + const MathGlyphInfo* mathglyphinfo = GetMathGlyphInfo(); + start = reinterpret_cast(mathglyphinfo); + if (!ValidStructure(start, sizeof(MathGlyphInfo))) { + return false; + } + + // Verify the MathVariants header. + const MathVariants* mathvariants = GetMathVariants(); + start = reinterpret_cast(mathvariants); + if (!ValidStructure(start, sizeof(MathVariants)) || + !ValidStructure(start, + sizeof(MathVariants) + sizeof(Offset) * + (uint16_t(mathvariants->mVertGlyphCount) + + uint16_t(mathvariants->mHorizGlyphCount))) || + !ValidOffset(start, uint16_t(mathvariants->mVertGlyphCoverage)) || + !ValidOffset(start, uint16_t(mathvariants->mHorizGlyphCoverage))) { + return false; + } + + return true; +} + +int32_t +gfxMathTable::GetMathConstant(gfxFontEntry::MathConstant aConstant) +{ + const MathConstants* mathconstants = GetMathConstants(); + + if (aConstant <= gfxFontEntry::ScriptScriptPercentScaleDown) { + return int16_t(mathconstants->mInt16[aConstant]); + } + + if (aConstant <= gfxFontEntry::DisplayOperatorMinHeight) { + return + uint16_t(mathconstants-> + mUint16[aConstant - gfxFontEntry::DelimitedSubFormulaMinHeight]); + } + + if (aConstant <= gfxFontEntry::RadicalKernAfterDegree) { + return int16_t(mathconstants-> + mMathValues[aConstant - gfxFontEntry::MathLeading].mValue); + } + + return uint16_t(mathconstants->mRadicalDegreeBottomRaisePercent); +} + +bool +gfxMathTable::GetMathItalicsCorrection(uint32_t aGlyphID, + int16_t* aItalicCorrection) +{ + const MathGlyphInfo* mathglyphinfo = GetMathGlyphInfo(); + + // Get the offset of the italic correction and verify whether it is valid. + const char* start = reinterpret_cast(mathglyphinfo); + uint16_t offset = mathglyphinfo->mMathItalicsCorrectionInfo; + if (offset == 0 || !ValidOffset(start, offset)) { + return false; + } + start += offset; + + // Verify the validity of the MathItalicsCorrectionInfo and retrieve it. + if (!ValidStructure(start, sizeof(MathItalicsCorrectionInfo))) { + return false; + } + const MathItalicsCorrectionInfo* italicsCorrectionInfo = + reinterpret_cast(start); + + // Get the coverage index for the glyph. + offset = italicsCorrectionInfo->mCoverage; + const Coverage* coverage = + reinterpret_cast(start + offset); + int32_t i = GetCoverageIndex(coverage, aGlyphID); + + // Get the ItalicsCorrection. + uint16_t count = italicsCorrectionInfo->mItalicsCorrectionCount; + if (i < 0 || i >= count) { + return false; + } + start = reinterpret_cast(italicsCorrectionInfo + 1); + if (!ValidStructure(start, count * sizeof(MathValueRecord))) { + return false; + } + const MathValueRecord* mathValueRecordArray = + reinterpret_cast(start); + + *aItalicCorrection = int16_t(mathValueRecordArray[i].mValue); + return true; +} + +uint32_t +gfxMathTable::GetMathVariantsSize(uint32_t aGlyphID, bool aVertical, + uint16_t aSize) +{ + // Select the glyph construction. + SelectGlyphConstruction(aGlyphID, aVertical); + if (!mGlyphConstruction) { + return 0; + } + + // Verify the validity of the array of the MathGlyphVariantRecord's and + // whether there is a variant of the requested size. + uint16_t count = mGlyphConstruction->mVariantCount; + const char* start = reinterpret_cast(mGlyphConstruction + 1); + if (aSize >= count || + !ValidStructure(start, count * sizeof(MathGlyphVariantRecord))) { + return 0; + } + + // Return the glyph index of the requested size variant. + const MathGlyphVariantRecord* recordArray = + reinterpret_cast(start); + return uint32_t(recordArray[aSize].mVariantGlyph); +} + +bool +gfxMathTable::GetMathVariantsParts(uint32_t aGlyphID, bool aVertical, + uint32_t aGlyphs[4]) +{ + // Get the glyph assembly corresponding to that (aGlyphID, aVertical) pair. + const GlyphAssembly* glyphAssembly = GetGlyphAssembly(aGlyphID, aVertical); + if (!glyphAssembly) { + return false; + } + + // Verify the validity of the array of GlyphPartRecord's and retrieve it. + uint16_t count = glyphAssembly->mPartCount; + const char* start = reinterpret_cast(glyphAssembly + 1); + if (!ValidStructure(start, count * sizeof(GlyphPartRecord))) { + return false; + } + const GlyphPartRecord* recordArray = + reinterpret_cast(start); + + // XXXfredw The structure of the Open Type Math table is a bit more general + // than the one currently used by the nsMathMLChar code, so we try to fallback + // in reasonable way. We use the approach of the copyComponents function in + // github.com/mathjax/MathJax-dev/blob/master/fonts/OpenTypeMath/fontUtil.py + // + // The nsMathMLChar code can use at most 3 non extender pieces (aGlyphs[0], + // aGlyphs[1] and aGlyphs[2]) and the extenders between these pieces should + // all be the same (aGlyphs[4]). Also, the parts of vertical assembly are + // stored from bottom to top in the Open Type MATH table while they are + // stored from top to bottom in nsMathMLChar. + + // Count the number of non extender pieces + uint16_t nonExtenderCount = 0; + for (uint16_t i = 0; i < count; i++) { + if (!(uint16_t(recordArray[i].mPartFlags) & PART_FLAG_EXTENDER)) { + nonExtenderCount++; + } + } + if (nonExtenderCount > 3) { + // Not supported: too many pieces + return false; + } + + // Now browse the list of pieces + + // 0 = look for a left/bottom glyph + // 1 = look for an extender between left/bottom and mid + // 2 = look for a middle glyph + // 3 = look for an extender between middle and right/top + // 4 = look for a right/top glyph + // 5 = no more piece expected + uint8_t state = 0; + + // First extender char found. + uint32_t extenderChar = 0; + + // Clear the aGlyphs table. + memset(aGlyphs, 0, sizeof(uint32_t) * 4); + + for (uint16_t i = 0; i < count; i++) { + + bool isExtender = uint16_t(recordArray[i].mPartFlags) & PART_FLAG_EXTENDER; + uint32_t glyph = recordArray[i].mGlyph; + + if ((state == 1 || state == 2) && nonExtenderCount < 3) { + // do not try to find a middle glyph + state += 2; + } + + if (isExtender) { + if (!extenderChar) { + extenderChar = glyph; + aGlyphs[3] = extenderChar; + } else if (extenderChar != glyph) { + // Not supported: different extenders + return false; + } + + if (state == 0) { // or state == 1 + // ignore left/bottom piece and multiple successive extenders + state = 1; + } else if (state == 2) { // or state == 3 + // ignore middle piece and multiple successive extenders + state = 3; + } else if (state >= 4) { + // Not supported: unexpected extender + return false; + } + + continue; + } + + if (state == 0) { + // copy left/bottom part + aGlyphs[mVertical ? 2 : 0] = glyph; + state = 1; + continue; + } + + if (state == 1 || state == 2) { + // copy middle part + aGlyphs[1] = glyph; + state = 3; + continue; + } + + if (state == 3 || state == 4) { + // copy right/top part + aGlyphs[mVertical ? 0 : 2] = glyph; + state = 5; + } + + } + + return true; +} + +bool +gfxMathTable::ValidStructure(const char* aStart, uint16_t aSize) +{ + unsigned int mathDataLength; + const char* mathData = hb_blob_get_data(mMathTable, &mathDataLength); + return (mathData <= aStart && + aStart + aSize <= mathData + mathDataLength); +} + +bool +gfxMathTable::ValidOffset(const char* aStart, uint16_t aOffset) +{ + unsigned int mathDataLength; + const char* mathData = hb_blob_get_data(mMathTable, &mathDataLength); + return (mathData <= aStart + aOffset && + aStart + aOffset < mathData + mathDataLength); +} + +const MATHTableHeader* +gfxMathTable::GetMATHTableHeader() +{ + const char* mathData = hb_blob_get_data(mMathTable, nullptr); + return reinterpret_cast(mathData); +} + +const MathConstants* +gfxMathTable::GetMathConstants() +{ + const char* mathData = hb_blob_get_data(mMathTable, nullptr); + return + reinterpret_cast(mathData + + uint16_t(GetMATHTableHeader()-> + mMathConstants)); +} + +const MathGlyphInfo* +gfxMathTable::GetMathGlyphInfo() +{ + const char* mathData = hb_blob_get_data(mMathTable, nullptr); + return + reinterpret_cast(mathData + + uint16_t(GetMATHTableHeader()-> + mMathGlyphInfo)); +} + +const MathVariants* +gfxMathTable::GetMathVariants() +{ + const char* mathData = hb_blob_get_data(mMathTable, nullptr); + return + reinterpret_cast(mathData + + uint16_t(GetMATHTableHeader()-> + mMathVariants)); +} + +const GlyphAssembly* +gfxMathTable::GetGlyphAssembly(uint32_t aGlyphID, bool aVertical) +{ + // Select the glyph construction. + SelectGlyphConstruction(aGlyphID, aVertical); + if (!mGlyphConstruction) { + return nullptr; + } + + // Get the offset of the glyph assembly and verify whether it is valid. + const char* start = reinterpret_cast(mGlyphConstruction); + uint16_t offset = mGlyphConstruction->mGlyphAssembly; + if (offset == 0 || !ValidOffset(start, offset)) { + return nullptr; + } + start += offset; + + // Verify the validity of the GlyphAssembly and return it. + if (!ValidStructure(start, sizeof(GlyphAssembly))) { + return nullptr; + } + return reinterpret_cast(start); +} + +int32_t +gfxMathTable::GetCoverageIndex(const Coverage* aCoverage, uint32_t aGlyph) +{ + if (uint16_t(aCoverage->mFormat) == 1) { + // Coverage Format 1: list of individual glyph indices in the glyph set. + const CoverageFormat1* table = + reinterpret_cast(aCoverage); + uint16_t count = table->mGlyphCount; + const char* start = reinterpret_cast(table + 1); + if (ValidStructure(start, count * sizeof(GlyphID))) { + const GlyphID* glyphArray = + reinterpret_cast(start); + uint32_t imin = 0, imax = count; + while (imin < imax) { + uint32_t imid = (imin + imax) >> 1; + uint16_t glyphMid = glyphArray[imid]; + if (glyphMid == aGlyph) { + return imid; + } + if (glyphMid < aGlyph) { + imin = imid + 1; + } else { + imax = imid; + } + } + } + } else if (uint16_t(aCoverage->mFormat) == 2) { + // Coverage Format 2: ranges of consecutive indices. + const CoverageFormat2* table = + reinterpret_cast(aCoverage); + uint16_t count = table->mRangeCount; + const char* start = reinterpret_cast(table + 1); + if (ValidStructure(start, count * sizeof(RangeRecord))) { + const RangeRecord* rangeArray = + reinterpret_cast(start); + uint32_t imin = 0, imax = count; + while (imin < imax) { + uint32_t imid = (imin + imax) >> 1; + uint16_t rStart = rangeArray[imid].mStart; + uint16_t rEnd = rangeArray[imid].mEnd; + if (rEnd < aGlyph) { + imin = imid + 1; + } else if (aGlyph < rStart) { + imax = imid; + } else { + return (uint16_t(rangeArray[imid].mStartCoverageIndex) + + aGlyph - rStart); + } + } + } + } + return -1; +} + +void +gfxMathTable::SelectGlyphConstruction(uint32_t aGlyphID, bool aVertical) +{ + if (mGlyphID == aGlyphID && mVertical == aVertical) { + // The (glyph, direction) pair is already selected: nothing to do. + return; + } + + // Update our cached values. + mVertical = aVertical; + mGlyphID = aGlyphID; + mGlyphConstruction = nullptr; + + // Get the coverage index for the new values. + const MathVariants* mathvariants = GetMathVariants(); + const char* start = reinterpret_cast(mathvariants); + uint16_t offset = (aVertical ? + mathvariants->mVertGlyphCoverage : + mathvariants->mHorizGlyphCoverage); + const Coverage* coverage = + reinterpret_cast(start + offset); + int32_t i = GetCoverageIndex(coverage, aGlyphID); + + // Get the offset to the glyph construction. + uint16_t count = (aVertical ? + mathvariants->mVertGlyphCount : + mathvariants->mHorizGlyphCount); + start = reinterpret_cast(mathvariants + 1); + if (i < 0 || i >= count) { + return; + } + if (!aVertical) { + start += uint16_t(mathvariants->mVertGlyphCount) * sizeof(Offset); + } + if (!ValidStructure(start, count * sizeof(Offset))) { + return; + } + const Offset* offsetArray = reinterpret_cast(start); + offset = uint16_t(offsetArray[i]); + + // Make mGlyphConstruction point to the desired glyph construction. + start = reinterpret_cast(mathvariants); + if (!ValidStructure(start + offset, sizeof(MathGlyphConstruction))) { + return; + } + mGlyphConstruction = + reinterpret_cast(start + offset); +} diff --git a/gfx/thebes/gfxMathTable.h b/gfx/thebes/gfxMathTable.h new file mode 100644 index 000000000000..d7aac7a3361a --- /dev/null +++ b/gfx/thebes/gfxMathTable.h @@ -0,0 +1,122 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GFX_MATH_TABLE_H +#define GFX_MATH_TABLE_H + +#include "gfxFont.h" + +struct Coverage; +struct GlyphAssembly; +struct MATHTableHeader; +struct MathConstants; +struct MathGlyphConstruction; +struct MathGlyphInfo; +struct MathVariants; + +/** + * Used by |gfxFontEntry| to represent the MATH table of an OpenType font. + * Each |gfxFontEntry| owns at most one |gfxMathTable| instance. + */ +class gfxMathTable +{ +public: + /** + * @param aMathTable The MATH table from the OpenType font + * + * The gfxMathTable object takes over ownership of the blob references + * that are passed in, and will hb_blob_destroy() them when finished; + * the caller should -not- destroy this reference. + */ + gfxMathTable(hb_blob_t* aMathTable); + + /** + * Releases our reference to the MATH table and cleans up everything else. + */ + ~gfxMathTable(); + + /** + * Returns the value of the specified constant from the MATH table. + */ + int32_t GetMathConstant(gfxFontEntry::MathConstant aConstant); + + /** + * If the MATH table contains an italic correction for that glyph, this + * function gets the value and returns true. Otherwise it returns false. + */ + bool + GetMathItalicsCorrection(uint32_t aGlyphID, int16_t* aItalicCorrection); + + /** + * @param aGlyphID glyph index of the character we want to stretch + * @param aVertical direction of the stretching (vertical/horizontal) + * @param aSize the desired size variant + * + * Returns the glyph index of the desired size variant or 0 if there is not + * any such size variant. + */ + uint32_t GetMathVariantsSize(uint32_t aGlyphID, bool aVertical, + uint16_t aSize); + + /** + * @param aGlyphID glyph index of the character we want to stretch + * @param aVertical direction of the stretching (vertical/horizontal) + * @param aGlyphs pre-allocated buffer of 4 elements where the glyph + * indexes (or 0 for absent parts) will be stored. The parts are stored in + * the order expected by the nsMathMLChar: Top (or Left), Middle, Bottom + * (or Right), Glue. + * + * Tries to fill-in aGlyphs with the relevant glyph indexes and returns + * whether the operation was successful. The function returns false if + * there is not any assembly for the character we want to stretch or if + * the format is not supported by the nsMathMLChar code. + * + */ + bool GetMathVariantsParts(uint32_t aGlyphID, bool aVertical, + uint32_t aGlyphs[4]); + +protected: + friend class gfxFontEntry; + // This allows gfxFontEntry to verify the validity of the main headers + // before starting to use the MATH table. + bool HasValidHeaders(); + +private: + // HarfBuzz blob where the MATH table is stored. + hb_blob_t* mMathTable; + + // Cached values for the latest (mGlyphID, mVertical) pair that has been + // accessed and the corresponding glyph construction. These are verified + // by SelectGlyphConstruction and updated if necessary. + // mGlyphConstruction will be set to nullptr if no construction is defined + // for the glyph. If non-null, its mGlyphAssembly and mVariantCount fields + // may be safely read, but no further validation will have been done. + const MathGlyphConstruction* mGlyphConstruction; + uint32_t mGlyphID; + bool mVertical; + void SelectGlyphConstruction(uint32_t aGlyphID, bool aVertical); + + // Access to some structures of the MATH table. + // These accessors just return a pointer, but do NOT themselves check the + // validity of anything. Until we've checked that HasValidHeaders (which + // does validate them) returns true, they might return pointers that cannot + // even safely be dereferenced. GetGlyphAssembly may return nullptr if the + // given glyph has no assembly defined. + const MATHTableHeader* GetMATHTableHeader(); + const MathConstants* GetMathConstants(); + const MathGlyphInfo* GetMathGlyphInfo(); + const MathVariants* GetMathVariants(); + const GlyphAssembly* GetGlyphAssembly(uint32_t aGlyphID, bool aVertical); + + // Verify whether a structure or an offset belongs to the math data and can + // be read safely. + bool ValidStructure(const char* aStructStart, uint16_t aStructSize); + bool ValidOffset(const char* aOffsetStart, uint16_t aOffset); + + // Get the coverage index of a glyph index from an Open Type coverage table + // or -1 if the glyph index is not found. + int32_t GetCoverageIndex(const Coverage* aCoverage, uint32_t aGlyph); +}; + +#endif diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index 78529cdcdb71..6e38fb2a731f 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -26,6 +26,7 @@ EXPORTS += [ 'gfxGradientCache.h', 'gfxImageSurface.h', 'gfxLineSegment.h', + 'gfxMathTable.h', 'gfxMatrix.h', 'gfxPath.h', 'gfxPattern.h', @@ -235,6 +236,7 @@ UNIFIED_SOURCES += [ 'gfxGraphiteShaper.cpp', 'gfxHarfBuzzShaper.cpp', 'gfxImageSurface.cpp', + 'gfxMathTable.cpp', 'gfxMatrix.cpp', 'gfxPath.cpp', 'gfxPattern.cpp', From cec6c49525ad0fcf411998a79ec3651319a41aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Wang?= Date: Wed, 23 Apr 2014 06:57:42 -0700 Subject: [PATCH 30/40] Bug 407059 - Part 2: Make nsMathMLChar use the MATH table. r=karlt --- layout/mathml/nsMathMLChar.cpp | 525 +++++++++++++++++++++++++++------ layout/mathml/nsMathMLChar.h | 2 + 2 files changed, 429 insertions(+), 98 deletions(-) diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp index 606b649851e2..7ea753a9527f 100644 --- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -28,10 +28,15 @@ #include "nsMathMLOperators.h" #include +#include "gfxMathTable.h" + using namespace mozilla; //#define NOISY_SEARCH 1 +static const float kLargeOpFactor = float(M_SQRT2); +static const float kIntegralFactor = 2.0; + // ----------------------------------------------------------------------------- static const nsGlyphCode kNullGlyph = {{{0, 0}}, 0}; typedef enum {eExtension_base, eExtension_variants, eExtension_parts} @@ -41,16 +46,59 @@ typedef enum {eExtension_base, eExtension_variants, eExtension_parts} // nsGlyphTable is a class that provides an interface for accessing glyphs // of stretchy chars. It acts like a table that stores the variants of bigger // sizes (if any) and the partial glyphs needed to build extensible symbols. -// An instance of nsGlyphTable is associated to one primary font. Extra glyphs -// can be taken in other additional fonts when stretching certain characters. -// These supplementary fonts are referred to as "external" fonts to the table. // -// Bigger sizes (if any) of the char can then be retrieved with -// BigOf(aSize). Partial glyphs can be retrieved with ElementAt() +// Bigger sizes (if any) of the char can then be retrieved with BigOf(...). +// Partial glyphs can be retrieved with ElementAt(...). // // A table consists of "nsGlyphCode"s which are viewed either as Unicode -// points or as direct glyph indices, depending on the type of the table. -// XXX The latter is not yet supported. +// points (for nsPropertiesTable) or as direct glyph indices (for +// nsOpenTypeTable) +// ----------------------------------------------------------------------------- + +class nsGlyphTable { +public: + virtual ~nsGlyphTable() {} + + virtual const nsAString& + FontNameFor(const nsGlyphCode& aGlyphCode) const = 0; + + // Getters for the parts + virtual nsGlyphCode ElementAt(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + char16_t aChar, + bool aVertical, + uint32_t aPosition) = 0; + virtual nsGlyphCode BigOf(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + char16_t aChar, + bool aVertical, + uint32_t aSize) = 0; + + // True if this table contains parts to render this char + virtual bool HasPartsOf(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + char16_t aChar, + bool aVertical) = 0; + + virtual gfxTextRun* MakeTextRun(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + const nsGlyphCode& aGlyph) = 0; +protected: + nsGlyphTable() : mCharCache(0) {} + // For speedy re-use, we always cache the last data used in the table. + // mCharCache is the Unicode point of the last char that was queried in this + // table. + char16_t mCharCache; +}; + +// An instance of nsPropertiesTable is associated with one primary font. Extra +// glyphs can be taken in other additional fonts when stretching certain +// characters. +// These supplementary fonts are referred to as "external" fonts to the table. // General format of MathFont Property Files from which glyph data are // retrieved: @@ -67,9 +115,6 @@ typedef enum {eExtension_base, eExtension_variants, eExtension_parts} // with the UNICODE REPLACEMENT CHARACTER 0xFFFD. // ----------------------------------------------------------------------------- -#define NS_TABLE_TYPE_UNICODE 0 -#define NS_TABLE_TYPE_GLYPH_INDEX 1 - #define NS_TABLE_STATE_ERROR -1 #define NS_TABLE_STATE_EMPTY 0 #define NS_TABLE_STATE_READY 1 @@ -98,23 +143,19 @@ LoadProperties(const nsString& aName, NS_ConvertUTF16toUTF8(uriStr)); } -// ----------------------------------------------------------------------------- - -class nsGlyphTable { +class nsPropertiesTable MOZ_FINAL : public nsGlyphTable { public: - explicit nsGlyphTable(const nsString& aPrimaryFontName) - : mFontName(1), // ensure space for primary font name. - mState(NS_TABLE_STATE_EMPTY), - mCharCache(0) + explicit nsPropertiesTable(const nsString& aPrimaryFontName) + : mFontName(1) // ensure space for primary font name. + , mState(NS_TABLE_STATE_EMPTY) { - MOZ_COUNT_CTOR(nsGlyphTable); + MOZ_COUNT_CTOR(nsPropertiesTable); mFontName.AppendElement(aPrimaryFontName); } - // not a virtual destructor: this class is not intended to be subclassed - ~nsGlyphTable() + ~nsPropertiesTable() { - MOZ_COUNT_DTOR(nsGlyphTable); + MOZ_COUNT_DTOR(nsPropertiesTable); } const nsAString& PrimaryFontName() const @@ -122,29 +163,52 @@ public: return mFontName[0]; } - const nsAString& FontNameFor(const nsGlyphCode& aGlyphCode) const + const nsAString& + FontNameFor(const nsGlyphCode& aGlyphCode) const MOZ_OVERRIDE { NS_ASSERTION(!aGlyphCode.IsGlyphID(), - "nsGlyphTable can only access glyphs by Unicode code point"); + "nsPropertiesTable can only access glyphs by code point"); return mFontName[aGlyphCode.font]; } - // Getters for the parts - nsGlyphCode ElementAt(char16_t aChar, uint32_t aPosition); - nsGlyphCode BigOf(char16_t aChar, int32_t aSize) { - return ElementAt(aChar, 4 + aSize); + virtual nsGlyphCode ElementAt(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + char16_t aChar, + bool aVertical, + uint32_t aPosition) MOZ_OVERRIDE; + + virtual nsGlyphCode BigOf(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + char16_t aChar, + bool aVertical, + uint32_t aSize) MOZ_OVERRIDE + { + return ElementAt(aThebesContext, aAppUnitsPerDevPixel, aFontGroup, + aChar, aVertical, 4 + aSize); } - // True if this table contains parts to render this char - bool HasPartsOf(char16_t aChar) { - return (ElementAt(aChar, 0).Exists() || ElementAt(aChar, 1).Exists() || - ElementAt(aChar, 2).Exists() || ElementAt(aChar, 3).Exists()); + virtual bool HasPartsOf(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + char16_t aChar, + bool aVertical) MOZ_OVERRIDE + { + return (ElementAt(aThebesContext, aAppUnitsPerDevPixel, aFontGroup, + aChar, aVertical, 0).Exists() || + ElementAt(aThebesContext, aAppUnitsPerDevPixel, aFontGroup, + aChar, aVertical, 1).Exists() || + ElementAt(aThebesContext, aAppUnitsPerDevPixel, aFontGroup, + aChar, aVertical, 2).Exists() || + ElementAt(aThebesContext, aAppUnitsPerDevPixel, aFontGroup, + aChar, aVertical, 3).Exists()); } - gfxTextRun* MakeTextRun(gfxContext* aThebesContext, - int32_t aAppUnitsPerDevPixel, - gfxFontGroup* aFontGroup, - const nsGlyphCode& aGlyph); + virtual gfxTextRun* MakeTextRun(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + const nsGlyphCode& aGlyph) MOZ_OVERRIDE; private: // mFontName[0] is the primary font associated to this table. The others @@ -159,10 +223,9 @@ private: // File nsCOMPtr mGlyphProperties; - // For speedy re-use, we always cache the last data used in the table. - // mCharCache is the Unicode point of the last char that was queried in this - // table. mGlyphCache is a buffer containing the glyph data associated to - // that char. For a property line 'key = value' in the MathFont Property File, + // mGlyphCache is a buffer containing the glyph data associated with + // mCharCache. + // For a property line 'key = value' in the MathFont Property File, // mCharCache will retain the 'key' -- which is a Unicode point, while // mGlyphCache will retain the 'value', which is a consecutive list of // nsGlyphCodes, i.e., the pairs of 'code@font' needed by the char -- in @@ -178,11 +241,16 @@ private: // table. Other digits map to the "external" fonts that may have been // specified in the MathFont Property File. nsString mGlyphCache; - char16_t mCharCache; }; +/* virtual */ nsGlyphCode -nsGlyphTable::ElementAt(char16_t aChar, uint32_t aPosition) +nsPropertiesTable::ElementAt(gfxContext* /* aThebesContext */, + int32_t /* aAppUnitsPerDevPixel */, + gfxFontGroup* /* aFontGroup */, + char16_t aChar, + bool /* aVertical */, + uint32_t aPosition) { if (mState == NS_TABLE_STATE_ERROR) return kNullGlyph; // Load glyph properties if this is the first time we have been here @@ -286,18 +354,205 @@ nsGlyphTable::ElementAt(char16_t aChar, uint32_t aPosition) return ch.code[0] == char16_t(0xFFFD) ? kNullGlyph : ch; } +/* virtual */ gfxTextRun* -nsGlyphTable::MakeTextRun(gfxContext* aThebesContext, - int32_t aAppUnitsPerDevPixel, - gfxFontGroup* aFontGroup, - const nsGlyphCode& aGlyph) +nsPropertiesTable::MakeTextRun(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + const nsGlyphCode& aGlyph) { - NS_ASSERTION(!aGlyph.IsGlyphID(), "not yet implemented"); + NS_ASSERTION(!aGlyph.IsGlyphID(), + "nsPropertiesTable can only access glyphs by code point"); return aFontGroup-> MakeTextRun(aGlyph.code, aGlyph.Length(), aThebesContext, aAppUnitsPerDevPixel, 0); } +// An instance of nsOpenTypeTable is associated with one gfxFontEntry that +// corresponds to an Open Type font with a MATH table. All the glyphs come from +// the same font and the calls to access size variants and parts are directly +// forwarded to the gfx code. +class nsOpenTypeTable MOZ_FINAL : public nsGlyphTable { +public: + ~nsOpenTypeTable() + { + MOZ_COUNT_DTOR(nsOpenTypeTable); + } + + virtual nsGlyphCode ElementAt(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + char16_t aChar, + bool aVertical, + uint32_t aPosition) MOZ_OVERRIDE; + virtual nsGlyphCode BigOf(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + char16_t aChar, + bool aVertical, + uint32_t aSize) MOZ_OVERRIDE; + virtual bool HasPartsOf(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + char16_t aChar, + bool aVertical) MOZ_OVERRIDE; + + const nsAString& + FontNameFor(const nsGlyphCode& aGlyphCode) const MOZ_OVERRIDE { + NS_ASSERTION(aGlyphCode.IsGlyphID(), + "nsOpenTypeTable can only access glyphs by id"); + return mFontEntry->FamilyName(); + } + + virtual gfxTextRun* MakeTextRun(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + const nsGlyphCode& aGlyph) MOZ_OVERRIDE; + + // This returns a new OpenTypeTable instance to give access to OpenType MATH + // table or nullptr if the font does not have such table. Ownership is passed + // to the caller. + static nsOpenTypeTable* Create(gfxFont* aFont) + { + if (!aFont->GetFontEntry()->TryGetMathTable(aFont)) { + return nullptr; + } + return new nsOpenTypeTable(aFont->GetFontEntry()); + } + +private: + nsRefPtr mFontEntry; + uint32_t mGlyphID; + + explicit nsOpenTypeTable(gfxFontEntry* aFontEntry) + : mFontEntry(aFontEntry) { + MOZ_COUNT_CTOR(nsOpenTypeTable); + } + + void UpdateCache(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + char16_t aChar); +}; + +void +nsOpenTypeTable::UpdateCache(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + char16_t aChar) +{ + if (mCharCache != aChar) { + nsAutoPtr textRun; + textRun = aFontGroup-> + MakeTextRun(&aChar, 1, aThebesContext, aAppUnitsPerDevPixel, 0); + const gfxTextRun::CompressedGlyph& data = textRun->GetCharacterGlyphs()[0]; + if (data.IsSimpleGlyph()) { + mGlyphID = data.GetSimpleGlyph(); + } else if (data.GetGlyphCount() == 1) { + mGlyphID = textRun->GetDetailedGlyphs(0)->mGlyphID; + } else { + mGlyphID = 0; + } + mCharCache = aChar; + } +} + +/* virtual */ +nsGlyphCode +nsOpenTypeTable::ElementAt(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + char16_t aChar, + bool aVertical, + uint32_t aPosition) +{ + UpdateCache(aThebesContext, aAppUnitsPerDevPixel, aFontGroup, aChar); + + uint32_t parts[4]; + if (!mFontEntry->GetMathVariantsParts(mGlyphID, aVertical, parts)) { + return kNullGlyph; + } + + uint32_t glyphID = parts[aPosition]; + if (!glyphID) { + return kNullGlyph; + } + nsGlyphCode glyph; + glyph.glyphID = glyphID; + glyph.font = -1; + return glyph; +} + +/* virtual */ +nsGlyphCode +nsOpenTypeTable::BigOf(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + char16_t aChar, + bool aVertical, + uint32_t aSize) +{ + UpdateCache(aThebesContext, aAppUnitsPerDevPixel, aFontGroup, aChar); + + uint32_t glyphID = + mFontEntry->GetMathVariantsSize(mGlyphID, aVertical, aSize); + if (!glyphID) { + return kNullGlyph; + } + + nsGlyphCode glyph; + glyph.glyphID = glyphID; + glyph.font = -1; + return glyph; +} + +/* virtual */ +bool +nsOpenTypeTable::HasPartsOf(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + char16_t aChar, + bool aVertical) +{ + UpdateCache(aThebesContext, aAppUnitsPerDevPixel, aFontGroup, aChar); + + uint32_t parts[4]; + if (!mFontEntry->GetMathVariantsParts(mGlyphID, aVertical, parts)) { + return false; + } + + return parts[0] || parts[1] || parts[2] || parts[3]; +} + +/* virtual */ +gfxTextRun* +nsOpenTypeTable::MakeTextRun(gfxContext* aThebesContext, + int32_t aAppUnitsPerDevPixel, + gfxFontGroup* aFontGroup, + const nsGlyphCode& aGlyph) +{ + NS_ASSERTION(aGlyph.IsGlyphID(), + "nsOpenTypeTable can only access glyphs by id"); + + gfxTextRunFactory::Parameters params = { + aThebesContext, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevPixel + }; + gfxTextRun* textRun = gfxTextRun::Create(¶ms, 1, aFontGroup, 0); + textRun->AddGlyphRun(aFontGroup->GetFontAt(0), gfxTextRange::kFontGroup, 0, + false); + gfxTextRun::DetailedGlyph detailedGlyph; + detailedGlyph.mGlyphID = aGlyph.glyphID; + // We set the advance width to zero and this will be fixed in MeasureTextRun. + // XXXfredw: We should use gfxHarfbuzzShaper::GetGlyphHAdvance() + detailedGlyph.mAdvance = 0; + detailedGlyph.mXOffset = detailedGlyph.mYOffset = 0; + gfxShapedText::CompressedGlyph g; + g.SetComplex(true, true, 1); + textRun->SetGlyphs(0, g, &detailedGlyph); + + return textRun; +} + // ----------------------------------------------------------------------------- // This is the list of all the applicable glyph tables. // We will maintain a single global instance that will only reveal those @@ -311,7 +566,7 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER - nsGlyphTable mUnicodeTable; + nsPropertiesTable mUnicodeTable; nsGlyphTableList() : mUnicodeTable(NS_LITERAL_STRING("Unicode")) @@ -336,15 +591,14 @@ public: GetGlyphTableFor(const nsAString& aFamily); private: - nsGlyphTable* TableAt(int32_t aIndex) { - return &mTableList.ElementAt(aIndex); + nsPropertiesTable* PropertiesTableAt(int32_t aIndex) { + return &mPropertiesTableList.ElementAt(aIndex); } - int32_t Count() { - return mTableList.Length(); + int32_t PropertiesTableCount() { + return mPropertiesTableList.Length(); } - // List of glyph tables; - nsTArray mTableList; + nsTArray mPropertiesTableList; }; NS_IMPL_ISUPPORTS1(nsGlyphTableList, nsIObserver) @@ -405,15 +659,15 @@ nsGlyphTableList::AddGlyphTable(const nsString& aPrimaryFontName) return glyphTable; // allocate a table - glyphTable = mTableList.AppendElement(aPrimaryFontName); + glyphTable = mPropertiesTableList.AppendElement(aPrimaryFontName); return glyphTable; } nsGlyphTable* nsGlyphTableList::GetGlyphTableFor(const nsAString& aFamily) { - for (int32_t i = 0; i < Count(); i++) { - nsGlyphTable* glyphTable = TableAt(i); + for (int32_t i = 0; i < PropertiesTableCount(); i++) { + nsPropertiesTable* glyphTable = PropertiesTableAt(i); const nsAString& fontName = glyphTable->PrimaryFontName(); // TODO: would be nice to consider StripWhitespace and other aliasing if (fontName.Equals(aFamily, nsCaseInsensitiveStringComparator())) { @@ -899,6 +1153,11 @@ MeasureTextRun(gfxContext* aThebesContext, gfxTextRun* aTextRun) bm.ascent = NSToCoordCeil(-metrics.mBoundingBox.Y()); bm.descent = NSToCoordCeil(metrics.mBoundingBox.YMost()); bm.width = NSToCoordRound(metrics.mAdvanceWidth); + if (bm.width == 0) { + // The advance width was not set in nsGlyphTable::MakeTextRun, so we use + // the right bearing instead. + bm.width = bm.rightBearing; + } return bm; } @@ -930,8 +1189,12 @@ public: EnumCallback(const nsString& aFamily, bool aGeneric, void *aData); private: - bool TryVariants(nsGlyphTable* aGlyphTable, const nsAString& aFamily); - bool TryParts(nsGlyphTable* aGlyphTable, const nsAString& aFamily); + bool TryVariants(nsGlyphTable* aGlyphTable, + nsRefPtr* aFontGroup, + const nsAString& aFamily); + bool TryParts(nsGlyphTable* aGlyphTable, + nsRefPtr* aFontGroup, + const nsAString& aFamily); nsMathMLChar* mChar; nsPresContext* mPresContext; @@ -957,14 +1220,18 @@ private: // Returns true if the size is OK, false to keep searching. // Always updates the char if a better match is found. bool -nsMathMLChar::StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable, - const nsAString& aFamily) +nsMathMLChar:: +StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable, + nsRefPtr* aFontGroup, + const nsAString& aFamily) { // Use our stretchy style context now that stretching is in progress nsStyleContext *sc = mChar->mStyleContext; nsFont font = sc->StyleFont()->mFont; bool isVertical = (mDirection == NS_STRETCH_DIRECTION_VERTICAL); + nscoord oneDevPixel = mPresContext->AppUnitsPerDevPixel(); + char16_t uchar = mChar->mData[0]; bool largeop = (NS_STRETCH_LARGEOP & mStretchHint) != 0; bool largeopOnly = largeop && (NS_STRETCH_VARIABLE_MASK & mStretchHint) == 0; @@ -977,17 +1244,45 @@ nsMathMLChar::StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable, // start at size = 1 (size = 0 is the char at its normal size) int32_t size = 1; + nsGlyphCode ch; + nscoord displayOperatorMinHeight = 0; + if (largeopOnly) { + NS_ASSERTION(isVertical, "Stretching should be in the vertical direction"); + ch = aGlyphTable->BigOf(mThebesContext, oneDevPixel, *aFontGroup, uchar, + isVertical, 0); + if (ch.IsGlyphID()) { + gfxFont* mathFont = aFontGroup->get()->GetFontAt(0); + // For OpenType MATH fonts, we will rely on the DisplayOperatorMinHeight + // to select the right size variant. Note that the value is sometimes too + // small so we use kLargeOpFactor/kIntegralFactor as a minimum value. + displayOperatorMinHeight = + NSToCoordRound(mathFont->GetFontEntry()-> + GetMathConstant(gfxFontEntry::DisplayOperatorMinHeight) * + mathFont->GetAdjustedSize() * oneDevPixel); + nsAutoPtr textRun; + textRun = aGlyphTable->MakeTextRun(mThebesContext, oneDevPixel, + *aFontGroup, ch); + nsBoundingMetrics bm = MeasureTextRun(mThebesContext, textRun); + float largeopFactor = kLargeOpFactor; + if (NS_STRETCH_INTEGRAL & mStretchHint) { + // integrals are drawn taller + largeopFactor = kIntegralFactor; + } + nscoord minHeight = largeopFactor * (bm.ascent + bm.descent); + if (displayOperatorMinHeight < minHeight) { + displayOperatorMinHeight = minHeight; + } + } + } #ifdef NOISY_SEARCH printf(" searching in %s ...\n", NS_LossyConvertUTF16toASCII(aFamily).get()); #endif - - nsGlyphCode ch; - nsRefPtr fontGroup; - while ((ch = aGlyphTable->BigOf(mChar->mData[0], size)).Exists()) { + while ((ch = aGlyphTable->BigOf(mThebesContext, oneDevPixel, *aFontGroup, + uchar, isVertical, size)).Exists()) { if (!mChar->SetFontFamily(mPresContext, aGlyphTable, ch, aFamily, font, - &fontGroup)) { + aFontGroup)) { // if largeopOnly is set, break now if (largeopOnly) break; ++size; @@ -995,10 +1290,29 @@ nsMathMLChar::StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable, } nsAutoPtr textRun; - textRun = aGlyphTable->MakeTextRun(mThebesContext, - mPresContext->AppUnitsPerDevPixel(), - fontGroup, ch); + textRun = aGlyphTable->MakeTextRun(mThebesContext, oneDevPixel, + *aFontGroup, ch); nsBoundingMetrics bm = MeasureTextRun(mThebesContext, textRun); + if (ch.IsGlyphID()) { + gfxFont* mathFont = aFontGroup->get()->GetFontAt(0); + if (mathFont->GetFontEntry()->TryGetMathTable(mathFont)) { + // MeasureTextRun has set the advance width to the right bearing. We now + // subtract the italic correction, so that nsMathMLmmultiscripts will + // place the scripts correctly. + // Note that STIX-Word does not provide italic corrections + // (http://sourceforge.net/p/stixfonts/tracking/50/) + gfxFloat italicCorrection; + if (mathFont->GetFontEntry()-> + GetMathItalicsCorrection(ch.glyphID, &italicCorrection)) { + bm.width -= + NSToCoordRound(italicCorrection * + mathFont->GetAdjustedSize() * oneDevPixel); + if (bm.width < 0) { + bm.width = 0; + } + } + } + } nscoord charSize = isVertical ? bm.ascent + bm.descent @@ -1038,8 +1352,10 @@ nsMathMLChar::StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable, break; // Not making an futher progress, stop searching } - // if largeopOnly is set, break now - if (largeopOnly) break; + // If this a largeop only operator, we stop if the glyph is large enough. + if (largeopOnly && (bm.ascent + bm.descent) >= displayOperatorMinHeight) { + break; + } ++size; } @@ -1052,14 +1368,10 @@ nsMathMLChar::StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable, // Returns true if the size is OK, false to keep searching. // Always updates the char if a better match is found. bool -nsMathMLChar::StretchEnumContext::TryParts(nsGlyphTable* aGlyphTable, +nsMathMLChar::StretchEnumContext::TryParts(nsGlyphTable* aGlyphTable, + nsRefPtr* aFontGroup, const nsAString& aFamily) { - if (!aGlyphTable->HasPartsOf(mChar->mData[0])) - return false; // to next table - - // See if the parts of this table fit in the desired space ////////////////// - // Use our stretchy style context now that stretching is in progress nsFont font = mChar->mStyleContext->StyleFont()->mFont; @@ -1070,20 +1382,24 @@ nsMathMLChar::StretchEnumContext::TryParts(nsGlyphTable* aGlyphTable, nscoord sizedata[4]; bool isVertical = (mDirection == NS_STRETCH_DIRECTION_VERTICAL); + nscoord oneDevPixel = mPresContext->AppUnitsPerDevPixel(); + char16_t uchar = mChar->mData[0]; bool maxWidth = (NS_STRETCH_MAXWIDTH & mStretchHint) != 0; - nsRefPtr fontGroup; + if (!aGlyphTable->HasPartsOf(mThebesContext, oneDevPixel, *aFontGroup, + uchar, isVertical)) + return false; // to next table for (int32_t i = 0; i < 4; i++) { - nsGlyphCode ch = aGlyphTable->ElementAt(mChar->mData[0], i); + nsGlyphCode ch = aGlyphTable->ElementAt(mThebesContext, oneDevPixel, + *aFontGroup, uchar, isVertical, i); chdata[i] = ch; if (ch.Exists()) { if (!mChar->SetFontFamily(mPresContext, aGlyphTable, ch, aFamily, font, - &fontGroup)) + aFontGroup)) return false; - textRun[i] = aGlyphTable->MakeTextRun(mThebesContext, - mPresContext->AppUnitsPerDevPixel(), - fontGroup, ch); + textRun[i] = aGlyphTable->MakeTextRun(mThebesContext, oneDevPixel, + *aFontGroup, ch); nsBoundingMetrics bm = MeasureTextRun(mThebesContext, textRun[i]); // TODO: For the generic Unicode table, ideally we should check that the @@ -1203,15 +1519,6 @@ nsMathMLChar::StretchEnumContext::EnumCallback(const nsString& aFamily, { StretchEnumContext* context = static_cast(aData); - // See if there is a special table for the family, but always use the - // Unicode table for generic fonts. - nsGlyphTable* glyphTable = aGeneric ? - &gGlyphTableList->mUnicodeTable : - gGlyphTableList->GetGlyphTableFor(aFamily); - - if (context->mTablesTried.Contains(glyphTable)) - return true; // already tried this one - // Check font family if it is not a generic one // We test with the kNullGlyph nsStyleContext *sc = context->mChar->mStyleContext; @@ -1222,10 +1529,31 @@ nsMathMLChar::StretchEnumContext::EnumCallback(const nsString& aFamily, font, &fontGroup)) return true; // Could not set the family - // Now see if the table has a glyph that matches the container + // Determine the glyph table to use for this font. + nsAutoPtr openTypeTable; + nsGlyphTable* glyphTable; + if (aGeneric) { + // This is a generic font, use the Unicode table. + glyphTable = &gGlyphTableList->mUnicodeTable; + } else { + // If the font contains an Open Type MATH table, use it. + openTypeTable = nsOpenTypeTable::Create(fontGroup->GetFontAt(0)); + if (openTypeTable) { + glyphTable = openTypeTable; + } else { + // Otherwise try to find a .properties file corresponding to that font + // family or fallback to the Unicode table. + glyphTable = gGlyphTableList->GetGlyphTableFor(aFamily); + } + } - // Only try this table once. - context->mTablesTried.AppendElement(glyphTable); + if (!openTypeTable) { + if (context->mTablesTried.Contains(glyphTable)) + return true; // already tried this one + + // Only try this table once. + context->mTablesTried.AppendElement(glyphTable); + } // If the unicode table is being used, then search all font families. If a // special table is being used then the font in this family should have the @@ -1233,8 +1561,9 @@ nsMathMLChar::StretchEnumContext::EnumCallback(const nsString& aFamily, const nsAString& family = glyphTable == &gGlyphTableList->mUnicodeTable ? context->mFamilies : aFamily; - if((context->mTryVariants && context->TryVariants(glyphTable, family)) || - (context->mTryParts && context->TryParts(glyphTable, family))) + if((context->mTryVariants && + context->TryVariants(glyphTable, &fontGroup, family)) || + (context->mTryParts && context->TryParts(glyphTable, &fontGroup, family))) return false; // no need to continue return true; // true means continue @@ -1470,7 +1799,7 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext, // apply a scale transform to the base char. if (!glyphFound && largeop) { float scale; - float largeopFactor = float(M_SQRT2); + float largeopFactor = kLargeOpFactor; // increase the width if it is not largeopFactor times larger // than the initial one. @@ -1491,7 +1820,7 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext, // than the initial one. if (NS_STRETCH_INTEGRAL & aStretchHint) { // integrals are drawn taller - largeopFactor = 2.0; + largeopFactor = kIntegralFactor; } if ((aDesiredStretchSize.ascent + aDesiredStretchSize.descent) < largeopFactor * (initialSize.ascent + initialSize.descent)) { diff --git a/layout/mathml/nsMathMLChar.h b/layout/mathml/nsMathMLChar.h index d1944b2d6710..1358a326150a 100644 --- a/layout/mathml/nsMathMLChar.h +++ b/layout/mathml/nsMathMLChar.h @@ -199,6 +199,8 @@ public: protected: friend class nsGlyphTable; + friend class nsPropertiesTable; + friend class nsOpenTypeTable; nsString mData; private: From dae40402cda5b99454f0ea306df4c57362ec3b4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Wang?= Date: Wed, 23 Apr 2014 06:57:42 -0700 Subject: [PATCH 31/40] Bug 407059 - Part 3: remove mathfontAsanaMath.properties and STIX 1.0 beta. r=karlt --- layout/mathml/mathfont.properties | 4 +- layout/mathml/mathfontAsanaMath.properties | 145 --------------------- layout/mathml/mathfontSTIXSize1.properties | 70 ---------- layout/mathml/moz.build | 2 - modules/libpref/src/init/all.js | 6 +- 5 files changed, 5 insertions(+), 222 deletions(-) delete mode 100644 layout/mathml/mathfontAsanaMath.properties delete mode 100644 layout/mathml/mathfontSTIXSize1.properties diff --git a/layout/mathml/mathfont.properties b/layout/mathml/mathfont.properties index 0685fb7033a2..ec911e2e4698 100644 --- a/layout/mathml/mathfont.properties +++ b/layout/mathml/mathfont.properties @@ -11,9 +11,9 @@ # each font. Do not include the Unicode table in this list. %ifdef XP_WIN -font.mathfont-glyph-tables = MathJax_Main, STIXNonUnicode, STIXSizeOneSym, STIXSize1, Asana Math, Standard Symbols L, Symbol +font.mathfont-glyph-tables = MathJax_Main, STIXNonUnicode, STIXSizeOneSym, Standard Symbols L, Symbol %else -font.mathfont-glyph-tables = MathJax_Main, STIXNonUnicode, STIXSizeOneSym, STIXSize1, Asana Math, Standard Symbols L +font.mathfont-glyph-tables = MathJax_Main, STIXNonUnicode, STIXSizeOneSym, Standard Symbols L %endif # The ordered list of fonts with which to attempt to stretch MathML diff --git a/layout/mathml/mathfontAsanaMath.properties b/layout/mathml/mathfontAsanaMath.properties deleted file mode 100644 index d697f3fbb53d..000000000000 --- a/layout/mathml/mathfontAsanaMath.properties +++ /dev/null @@ -1,145 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -# LOCALIZATION NOTE: FILE -# Do not translate anything in this file - -# This file contains the list of some stretchy MathML chars that -# can be rendered with Asana Math font. - -# [ T/L | M | B/R | G | size0 ... size{N-1} ] -# (*) not in the MathML operator dictionary - -\u0028 = \u239B\uFFFD\u239D\u239C\u0028\uDBFF\uDFF4\uDBFF\uDFF5\uDBFF\uDFF6 # ( -\u0029 = \u239E\uFFFD\u23A0\u239F\u0029\uDBFF\uDFF7\uDBFF\uDFF8\uDBFF\uDFF9 # ) -\u005B = \u23A1\uFFFD\u23A3\u23A2\u005B\uDBFF\uDFEE\uDBFF\uDFEF\uDBFF\uDFF0 # [ -\u005D = \u23A4\uFFFD\u23A6\u23A5\u005D\uDBFF\uDFF1\uDBFF\uDFF2\uDBFF\uDFF3 # ] -\u007B = \u23A7\u23A8\u23A9\u23AA\u007B\uDBFF\uDFFA\uDBFF\uDFFB\uDBFF\uDFFC # { -\u007C = \uFFFD\uFFFD\uFFFD\u007C\u007C\uDBFF\uDFD6\uDBFF\uDFD7\uDBFF\uDFD8\uDBFF\uDFD9 # | -\u007D = \u23AB\u23AC\u23AD\u23AA\u007D\uDBFF\uDFFD\uDBFF\uDFFE\uDBFF\uDFFF # } -\u2016 = \uFFFD\uFFFD\uFFFD\uDBFF\uDFD1\u2016\uDBFF\uDFCE\uDBFF\uDFCF\uDBFF\uDFD0\uDBFF\uDFD1 # DOUBLE VERTICAL LINE - -\u2044 = \uFFFD\uFFFD\uFFFD\uFFFD\u2044\uDBFF\uDFD2\uDBFF\uDFD3\uDBFF\uDFD4\uDBFF\uDFD5 # FRACTION SLASH -# \u2045 = \uDBFF\uDFB6\uDBFF\uDF53\uDBFF\uDFB7\uDBFF\uDFBA\u2045\uDBFF\uDFBB\uDBFF\uDFBC\uDBFF\uDFBD # LEFT SQUARE BRACKET WITH QUILL (*) -# \u2046 = \uDBFF\uDFB8\uDBFF\uDF54\uDBFF\uDFB9\uDBFF\uDF52\u2046\uDBFF\uDFBE\uDBFF\uDFBF\uDBFF\uDFC0 # RIGHT SQUARE BRACKET WITH QUILL (*) - -\u2191 = \u2191\uFFFD\uFFFD\uDBFF\uDEC6\u2191 # UPWARDS ARROW -\u2193 = \uFFFD\uFFFD\u2193\uDBFF\uDEC6\u2193 # DOWNWARDS ARROW -\u21D1 = \u21D1\uFFFD\uFFFD\uDBFF\uDEC7\u21D1 # UPWARDS DOUBLE ARROW -\u21D3 = \uFFFD\uFFFD\u21D3\uDBFF\uDEC7\u21D3 # DOWNWARDS DOUBLE ARROW - -\u220F = \uFFFD\uFFFD\uFFFD\uFFFD\u220F\uDBFF\uDF9F\uDBFF\uDFA0\uDBFF\uDFA1 # N-ARY PRODUCT -\u2210 = \uFFFD\uFFFD\uFFFD\uFFFD\u2210\uDBFF\uDFA2\uDBFF\uDFA3\uDBFF\uDFA4 # N-ARY COPRODUCT -\u2211 = \uFFFD\uFFFD\uFFFD\uFFFD\u2211\uDBFF\uDF9C\uDBFF\uDF9D\uDBFF\uDF9E # summation N-ARY SUMMATION -\u221A = \uDBFF\uDF6D\uFFFD\u23B7\u20D3\u221A\uDBFF\uDF6E\uDBFF\uDF6F\uDBFF\uDF70\uDBFF\uDF71 # SQUARE ROOT -\u2223 = \uFFFD\uFFFD\uFFFD\u2223\u2223 # DIVIDES -\u2225 = \uFFFD\uFFFD\uFFFD\u2225\u2225 # PARALLEL TO -\u222B = \u2320\uFFFD\u2321\u23AE\u222B\uDBFF\uDF99\uDBFF\uDF9A\uDBFF\uDF9B # INTEGRAL -\u222C = \uFFFD\uFFFD\uFFFD\uFFFD\u222C\uDBFF\uDF6A\uDBFF\uDF6B\uDBFF\uDF6C # DOUBLE INTEGRAL -\u222D = \uFFFD\uFFFD\uFFFD\uFFFD\u222D\uDBFF\uDF67\uDBFF\uDF68\uDBFF\uDF69 # TRIPLE INTEGRAL -\u222E = \uFFFD\uFFFD\uFFFD\uFFFD\u222E\uDBFF\uDF64\uDBFF\uDF65\uDBFF\uDF66 # CONTOUR INTEGRAL -\u222F = \uFFFD\uFFFD\uFFFD\uFFFD\u222F\uDBFF\uDF61\uDBFF\uDF62\uDBFF\uDF63 # SURFACE INTEGRAL -\u2230 = \uFFFD\uFFFD\uFFFD\uFFFD\u2230\uDBFF\uDF5E\uDBFF\uDF5F\uDBFF\uDF60 # VOLUME INTEGRAL -\u2231 = \uFFFD\uFFFD\uFFFD\uFFFD\u2231\uDBFF\uDF5B\uDBFF\uDF5C\uDBFF\uDF5D # CLOCKWISE INTEGRAL -\u2232 = \uFFFD\uFFFD\uFFFD\uFFFD\u2232\uDBFF\uDF58\uDBFF\uDF59\uDBFF\uDF5A # CLOCKWISE CONTOUR INTEGRAL -\u2233 = \uFFFD\uFFFD\uFFFD\uFFFD\u2233\uDBFF\uDF55\uDBFF\uDF56\uDBFF\uDF57 # ANTICLOCKWISE CONTOUR INTEGRAL - -\u22C0 = \uFFFD\uFFFD\uFFFD\uFFFD\u22C0\uDBFF\uDF92\uDBFF\uDF93 # N-ARY LOGICAL AND -\u22C1 = \uFFFD\uFFFD\uFFFD\uFFFD\u22C1\uDBFF\uDF94\uDBFF\uDF95 # N-ARY LOGICAL OR -\u22C2 = \uFFFD\uFFFD\uFFFD\uFFFD\u22C2\uDBFF\uDF8E\uDBFF\uDF8F # N-ARY INTERSECTION -\u22C3 = \uFFFD\uFFFD\uFFFD\uFFFD\u22C3\uDBFF\uDF8C\uDBFF\uDF8D # N-ARY UNION -\u2308 = \u23A1\uFFFD\uFFFD\u23A2\u2308\uDBFF\uDFE2\uDBFF\uDFE3\uDBFF\uDFE4 # LEFT CEILING -\u2309 = \u23A4\uFFFD\uFFFD\u23A5\u2309\uDBFF\uDFE5\uDBF\uDFE6\uDBFF\uDFE7 # RIGHT CEILING -\u230A = \uFFFD\uFFFD\u23A3\u23A2\u230A\uDBFF\uDFE8\uDBFF\uDFE9\uDBFF\uDFEA # LEFT FLOOR -\u230B = \uFFFD\uFFFD\u23A6\u23A5\u230B\u230B\uDBFF\uDFEB\uDBFF\uDFEC\uDBFF\uDFED # RIGHT FLOOR - -# \u27C5 = \uFFFD\uFFFD\uFFFD\uFFFD\u27C5\uDBFF\uDDF3\uDBFF\uDDF5\uDBFF\uDDF7\uDBFF\uDDF9\uDBFF\uDDFB # LEFT S-SHAPED BAG DELIMITER (*) -# \u27C6 = \uFFFD\uFFFD\uFFFD\uFFFD\uDBFF\uDDF4\uDBFF\uDDF6\uDBFF\uDDF8\uDBFF\uDDFA\uDBFF\uDDFC # RIGHT S-SHAPED BAG DELIMITER (*) -\u27E6 = \uFFFD\uFFFD\uFFFD\uFFFD\u27E6\uDBFF\uDFDA\uDBFF\uDFDB\uDBFF\uDFDC\uDBFF\uDFDD # MATHEMATICAL LEFT WHITE SQUARE BRACKET -\u27E7 = \uFFFD\uFFFD\uFFFD\uFFFD\u27E7\uDBFF\uDFDE\uDBFF\uDFDF\uDBFF\uDFE0\uDBFF\uDFE1 # MATHEMATICAL RIGHT WHITE SQUARE BRACKET -\u27E8 = \uFFFD\uFFFD\uFFFD\uFFFD\u27E8\uDBFF\uDF89\uDBFF\uDF8A\uDBFF\uD8B # MATHEMATICAL LEFT ANGLE BRACKET -\u27E9 = \uFFFD\uFFFD\uFFFD\uFFFD\u27E9\uDBFF\uDF7C\uDBFF\uDF7D\uDBFF\uDF7E # MATHEMATICAL RIGHT ANGLE BRACKET -\u27EA = \uFFFD\uFFFD\uFFFD\uFFFD\u27EA\uDBFF\uDF76\uDBFF\uDF77\uDBFF\uDF78 # MATHEMATICAL LEFT DOUBLE ANGLE BRACKET -\u27EB = \uFFFD\uFFFD\uFFFD\uFFFD\u27EB\uDBFF\uDF79\uDBFF\uDF7A\uDBFF\uDF7B # MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET - -\u29FC = \uFFFD\uFFFD\uFFFD\uFFFD\u29FC\uDBFF\uDEC8\uDBFF\uDEC9\uDBFF\uDECA # LEFT-POINTING CURVED ANGLE BRACKET -\u29FD = \uFFFD\uFFFD\uFFFD\uFFFD\u29FD\uDBFF\uDECB\uDBFF\uDECC\uDBFF\uDECD # RIGHT-POINTING CURVED ANGLE BRACKET - -\u2A00 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A00\uDBFF\uDF96\uDBFF\uDF97 # N-ARY CIRCLED DOT OPERATOR -\u2A01 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A01\uDBFF\uDF98\uDBFF\uDFA5 # N-ARY CIRCLED PLUS OPERATOR -\u2A02 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A02\uDBFF\uDF7F\uDBFF\uDF80 # N-ARY CIRCLED TIMES OPERATOR -\u2A03 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A03\uDBFF\uDF81\uDBFF\uDF82 # N-ARY UNION OPERATOR WITH DOT -\u2A04 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A04\uDBFF\uDF90\uDBFF\uDF91 # N-ARY UNION OPERATOR WITH PLUS -\u2A05 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A05\uDBFF\uDF83\uDBFF\uDF84 # N-ARY SQUARE INTERSECTION OPERATOR -\u2A06 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A06\uDBFF\uDF85\uDBFF\uDF86 # N-ARY SQUARE UNION OPERATOR -\u2A07 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A07\uDBFF\uDF72\uDBFF\uDF73 # TWO LOGICAL AND OPERATOR -\u2A08 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A08\uDBFF\uDF74\uDBFF\uDF75 # TWO LOGICAL OR OPERATOR -\u2A09 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A09\uDBFF\uDF87\uDBFF\uDF88 # N-ARY TIMES OPERATOR -\u2A0C = \uFFFD\uFFFD\uFFFD\uFFFD\u2A0C\uDBFF\uDF1F\uDBFF\uDF20\uDBFF\uDF21 # QUADRUPLE INTEGRAL OPERATOR -\u2A0D = \uFFFD\uFFFD\uFFFD\uFFFD\u2A0D\uDBFF\uDF22\uDBFF\uDF23\uDBFF\uDF24 # FINITE PART INTEGRAL -\u2A0E = \uFFFD\uFFFD\uFFFD\uFFFD\u2A0E\uDBFF\uDF25\uDBFF\uDF26\uDBFF\uDF27 # INTEGRAL WITH DOUBLE STROKE -\u2A0F = \uFFFD\uFFFD\uFFFD\uFFFD\u2A0F\uDBFF\uDF28\uDBFF\uDF29\uDBFF\uDF2A # INTEGRAL AVERAGE WITH SLASH -\u2A10 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A10\uDBFF\uDF2B\uDBFF\uDF2C\uDBFF\uDF2D # CIRCULATION FUNCTION -\u2A11 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A11\uDBFF\uDF2E\uDBFF\uDF2F\uDBFF\uDF30 # ANTICLOCKWISE INTEGRATION -\u2A12 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A12\uDBFF\uDF31\uDBFF\uDF32\uDBFF\uDF33 # LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE -\u2A13 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A13\uDBFF\uDF34\uDBFF\uDF35\uDBFF\uDF36 # LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE -\u2A14 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A14\uDBFF\uDF37\uDBFF\uDF38\uDBFF\uDF39 # LINE INTEGRATION NOT INCLUDING THE POLE -\u2A15 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A15\uDBFF\uDF3A\uDBFF\uDF3B\uDBFF\uDF3C # INTEGRAL AROUND A POINT OPERATOR -\u2A16 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A16\uDBFF\uDF3D\uDBFF\uDF3E\uDBFF\uDF3F # QUATERNION INTEGRAL OPERATOR -\u2A17 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A17\uDBFF\uDF40\uDBFF\uDF41\uDBFF\uDF42 # INTEGRAL WITH LEFTWARDS ARROW WITH HOOK -\u2A18 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A18\uDBFF\uDF43\uDBFF\uDF44\uDBFF\uDF45 # INTEGRAL WITH TIMES SIGN -\u2A19 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A19\uDBFF\uDF46\uDBFF\uDF47\uDBFF\uDF48 # INTEGRAL WITH INTERSECTION -\u2A1A = \uFFFD\uFFFD\uFFFD\uFFFD\u2A1A\uDBFF\uDF49\uDBFF\uDF4A\uDBFF\uDF4B # INTEGRAL WITH UNION -\u2A1B = \uFFFD\uFFFD\uFFFD\uFFFD\u2A1B\uDBFF\uDF4C\uDBFF\uDF4D\uDBFF\uDF4E # INTEGRAL WITH OVERBAR -\u2A1C = \uFFFD\uFFFD\uFFFD\uFFFD\u2A1C\uDBFF\uDF4F\uDBFF\uDF50\uDBFF\uDF51 # INTEGRAL WITH UNDERBAR - -\u005E = \uFFFD\uFFFD\uFFFD\uFFFD\u005E\uDBFF\uDFA6\uDBFF\uDFA7\uDBFF\uDFA8 # CIRCUMFLEX ACCENT -\u0302 = \uFFFD\uFFFD\uFFFD\uFFFD\u005E\uDBFF\uDFA6\uDBFF\uDFA7\uDBFF\uDFA8 # COMBINING CIRCUMFLEX ACCENT -\u007E = \uFFFD\uFFFD\uFFFD\uFFFD\u007E\uDBFF\uDFAA\uDBFF\uDFAB\uDBFF\uDFAC\uDBFF\uDFAD # TILDE -\u02DC = \uFFFD\uFFFD\uFFFD\uFFFD\u007E\uDBFF\uDFAA\uDBFF\uDFAB\uDBFF\uDFAC\uDBFF\uDFAD # SMALL TILDE -# \u0303 = \uFFFD\uFFFD\uFFFD\uFFFD\u007E\uDBFF\uDFAA\uDBFF\uDFAB\uDBFF\uDFAC\uDBFF\uDFAD # COMBINING TILDE (*) -# \u0305 = \uFFFD\uFFFD\uFFFD\uDBFF\uDF1E\u0305 COMBINING OVERLINE (*) -# \u0306 = \uFFFD\uFFFD\uFFFD\uFFFD\u02D8\uDBFF\uDFB2\uDBFF\uDFB3\uDBFF\uDFB4\uDBFF\uDFB5 # COMBINING BREVE (*) -# \u02D8 = \uFFFD\uFFFD\uFFFD\uFFFD\u02D8\uDBFF\uDFB2\uDBFF\uDFB3\uDBFF\uDFB4\uDBFF\uDFB5 # BREVE (not stretchy) -\u02C7 = \uFFFD\uFFFD\uFFFD\uFFFD\u02C7\uDBFF\uDFAE\uDBFF\uDFAF\uDBFF\uDFB0\uDBFF\uDFB1 # CARON -# \u030C = \uFFFD\uFFFD\uFFFD\uFFFD\u02C7\uDBFF\uDFAE\uDBFF\uDFAF\uDBFF\uDFB0\uDBFF\uDFB1 # COMBINING CARON (*) -# \u0332 = \uFFFD\uFFFD\uFFFD\uDBFF\uDF1D\u0332\uDBFF\uDF1D\uDBFF\uDF18\uDBFF\uDF14 # COMBINING LOW LINE (*) -# \u0333 = \uFFFD\uFFFD\uFFFD\uDBFF\uDF1C\u0333\uDBFF\uDF1C\uDBFF\uDF17\uDBFF\uDF13 # COMBINING DOUBLE LOW LINE (*) -# \u033F = \uFFFD\uFFFD\uFFFD\uDBFF\uDF1B\u033F\uDBFF\uDF1B\uDBFF\uDF16\uDBFF\uDF12 # COMBINING DOUBLE OVERLINE (*) -# \u20D0 = \u20D0\uFFFD\uFFFD\uDBFF\uDF1A\u20D0 # COMBINING LEFT HARPOON ABOVE (*) -# \u20D1 = \uFFFD\uFFFD\u20D1\uDBFF\uDF1A\u20D1 # COMBINING RIGHT HARPOON ABOVE (*) -# \u20D6 = \u20D6\uFFFD\uFFFD\uDBFF\uDF1A\u20D6\uDBFF\uDE4A\uDBFF\uDE4B\uDBFF\uDE4C\uDBFF\uDE4D # COMBINING LEFT ARROW ABOVE (*) -# \u20D7 = \uFFFD\uFFFD\u20D7\uDBFF\uDF1A\u20D7\uDBFF\uDE4E\uDBFF\uDE4F\uDBFF\uDE50\uDBFF\uDE51 # COMBINING RIGHT ARROW ABOVE (*) -# \u20E1 = \u20D6\uFFFD\u20D7\uDBFF\uDF1A\u20E1 # COMBINING LEFT RIGHT ARROW ABOVE (*) -# \u20E9 = \uDBFF\uDEEC\uFFFD\uDBFF\uDEED\uDBFF\uDEEB\u20E9 # COMBINING WIDE BRIDGE ABOVE (*) - -\u2190 = \uDBFF\uDF11\uFFFD\uDBFF\uDF10\u23AF\u2190 # LEFTWARDS ARROW -\u2192 = \uDBFF\uDF0E\uFFFD\uDBFF\uDF0F\u23AF\u2192 # RIGHTWARDS ARROW -\u2194 = \uDBFF\uDF11\uFFFD\uDBFF\uDF0F\u23AF\u2194 # LEFT RIGHT ARROW -\u21A4 = \uDBFF\uDF11\uFFFD\uDBFF\uDF08\u23AF\u21A4 # LEFTWARDS ARROW FROM BAR -\u21A6 = \uDBFF\uDF07\uFFFD\uDBFF\uDF0F\u23AF\u21A6 # RIGHTWARDS ARROW FROM BAR -\u21A9 = \uDBFF\uDF11\uFFFD\uDBFF\uDF06\u23AF\u21A9 # LEFTWARDS ARROW WITH HOOK -\u21AA = \uDBFF\uDF05\uFFFD\uDBFF\uDF0F\u23AF\u21AA # RIGHTWARDS ARROW WITH HOOK - -\u21D0 = \uDBFF\uDF0D\uFFFD\uDBFF\uDF0C\uDBFF\uDF09\u21D0 # LEFTWARDS DOUBLE ARROW -\u21D2 = \uDBFF\uDF0A\uFFFD\uDBFF\uDF0B\uDBFF\uDF09\u21D2 # RIGHTWARDS DOUBLE ARROW -\u21D4 = \uDBFF\uDF0D\uFFFD\uDBFF\uDF0B\uDBFF\uDF09\u21D4 # LEFT RIGHT DOUBLE ARROW - -\u23B4 = \uDBFF\uDEEC\uFFFD\uDBFF\uDEED\uDBFF\uDEEB\u23B4\uDBFF\uDEFD\uDBFF\uDEFE\uDBFF\uDEFF # TOP SQUARE BRACKET -\u23B5 = \uDBFF\uDEEE\uFFFD\uDBFF\uDEEF\uDBFF\uDEEA\u23B5\uDBFF\uDF00\uDBFF\uDF01\uDBFF\uDF02 # BOTTOM SQUARE BRACKET - -\u23DC = \uDBFF\uDFC7\uFFFD\uDBFF\uDFC9\uDBFF\uDFCA\u23DC\uDBFF\uDEF7\uDBFF\uDEF8\uDBFF\uDEF9 # TOP PARENTHESIS -\uFE35 = \uDBFF\uDFC7\uFFFD\uDBFF\uDFC9\uDBFF\uDFCA\u23DC\uDBFF\uDEF7\uDBFF\uDEF8\uDBFF\uDEF9 # ⏜ (MathML 2.0) -\u23DD = \uDBFF\uDFCB\uFFFD\uDBFF\uDFCD\uDBFF\uDEF0\u23DD\uDBFF\uDEFA\uDBFF\uDEFB\uDBFF\uDEFC # BOTTOM PARENTHESIS -\uFE36 = \uDBFF\uDFCB\uFFFD\uDBFF\uDFCD\uDBFF\uDEF0\u23DD\uDBFF\uDEFA\uDBFF\uDEFB\uDBFF\uDEFC # ⏝ (MathML 2.0) - -\u23DE = \uDBFF\uDFC7\uDBFF\uDFC8\uDBFF\uDFC9\uDBFF\uDFCA\u23DE\uDBFF\uDFC1\uDBFF\uDFC2\uDBFF\uDFC3 # TOP CURLY BRACKET -\uFE37 = \uDBFF\uDFC7\uDBFF\uDFC8\uDBFF\uDFC9\uDBFF\uDFCA\u23DE\uDBFF\uDFC1\uDBFF\uDFC2\uDBFF\uDFC3 # ⏞ (MathML 2.0) -\u23DF = \uDBFF\uDFCB\uDBFF\uDFCC\uDBFF\uDFCD\uDBFF\uDEF0\u23DF\uDBFF\uDFC4\uDBFF\uDFC5\uDBFF\uDFC6 # BOTTOM CURLY BRACKET -\uFE38 = \uDBFF\uDFCB\uDBFF\uDFCC\uDBFF\uDFCD\uDBFF\uDEF0\u23DF\uDBFF\uDFC4\uDBFF\uDFC5\uDBFF\uDFC6 # ⏟ (MathML 2.0) -\u23E0 = \uFFFD\uFFFD\uFFFD\uFFFD\u23E0\uDBFF\uDEF1\uDBFF\uDEF2\uDBFF\uDEF3 # TOP TORTOISE SHELL BRACKET -\u23E1 = \uFFFD\uFFFD\uFFFD\uFFFD\u23E1\uDBFF\uDEF4\uDBFF\uDEF5\uDBFF\uDEF6 # BOTTOM TORTOISE SHELL BRACKET - -\u2906 = \uDBFF\uDF0D\uFFFD\uDBFF\uDF04\uDBFF\uDF09\u2906 # LEFTWARDS DOUBLE ARROW FROM BAR -\u2907 = \uDBFF\uDF03\uFFFD\uDBFF\uDF0B\uDBFF\uDF09\u2907 # RIGHTWARDS DOUBLE ARROW FROM BAR diff --git a/layout/mathml/mathfontSTIXSize1.properties b/layout/mathml/mathfontSTIXSize1.properties deleted file mode 100644 index 5828865118a5..000000000000 --- a/layout/mathml/mathfontSTIXSize1.properties +++ /dev/null @@ -1,70 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -# LOCALIZATION NOTE: FILE -# Do not translate anything in this file - -# This file contains the list of some stretchy MathML chars that -# can be rendered with STIXSize* set of fonts, -# with some help from STIXNonUnicode and STIXGeneral. - -external.1 = STIXNonUnicode -external.2 = STIXSize2 -external.3 = STIXSize3 -external.4 = STIXSize4 -external.5 = STIXSize5 -external.6 = STIXGeneral - -# [ T/L | M | B/R | G | size0 ... size{N-1} ] -\u0028 = \u239B\uFFFD\u239D\u239C\uFFFD((@2(@3(@4 # ( -\u0029 = \u239E\uFFFD\u23A0\u239F\uFFFD))@2)@3)@4 # ) -\u005B = \u23A1\uFFFD\u23A3\u23A2\u005B[[@2[@3[@4 # [ -\u005D = \u23A4\uFFFD\u23A6\u23A5\u005D]]@2]@3]@4 # ] -\u007B = \u23A7\u23A8\u23A9\u23AA\u007B{{@2{@3{@4 # { -\u007D = \u23AB\u23AC\u23AD\u23AA\u007D}}@2}@3}@4 # } - -# N-ARY operators -\u2140 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2140 # DOUBLE-STRUCK N-ARY SUMMATION -\u220F = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u220F # N-ARY PRODUCT -\u2210 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2210 # N-ARY COPRODUCT -\u2211 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2211 # N-ARY SUMMATION -\u22C0 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u22C0 # N-ARY LOGICAL AND -\u22C1 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u22C1 # N-ARY LOGICAL OR -\u22C2 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u22C2 # N-ARY INTERSECTION -\u22C3 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u22C3 # N-ARY UNION -\u2A00 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A00 # N-ARY CIRCLED DOT OPERATOR -\u2A01 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A01 # N-ARY CIRCLED PLUS OPERATOR -\u2A02 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A02 # N-ARY CIRCLED TIMES OPERATOR -\u2A03 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A03 # N-ARY UNION OPERATOR WITH DOT -\u2A04 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A04 # N-ARY UNION OPERATOR WITH PLUS -\u2A05 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A05 # N-ARY SQUARE INTERSECTION OPERATOR -\u2A06 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A06 # N-ARY SQUARE UNION OPERATOR -\u2A09 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A09 # N-ARY TIMES OPERATOR -\u2AFF = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2AFF # N-ARY WHITE VERTICAL BAR - -# E000 stix-radical symbol vertical extender -# E001 stix-radical symbol top corner -\u221A = \uE001@1\uFFFD\u221A@4\uE000@1\uFFFD\u221A\u221A@2\u221A@3 # Sqrt, radic - -\u222B = \u2320\uFFFD\u2321\u23AE\uFFFD\u222B@6 # Integral, int - -\u27E8 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u27E8\u27E8@2\u27E8@3\u27E8@4 # LeftAngleBracket -\u27E9 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u27E9\u27E9@2\u27E9@3\u27E9@4 # RightAngleBracket - -\u23DE = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u23DE\u23DE@2\u23DE@3\u23DE@4\u23DE@5 # ⏞ (Unicode) -\uFE37 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u23DE\u23DE@2\u23DE@3\u23DE@4\u23DE@5 # ⏞ (MathML 2.0) -\u23B4 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u23B4\u23B4@2\u23B4@3\u23B4@4\u23B4@5 # ⎴ -\u23DC = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u23DC\u23DC@2\u23DC@3\u23DC@4\u23DC@5 # ⏜ (Unicode) -\uFE35 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u23DC\u23DC@2\u23DC@3\u23DC@4\u23DC@5 # ⏜ (MathML 2.0) -\u23DF = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u23DF\u23DF@2\u23DF@3\u23DF@4\u23DF@5 # ⏟ (Unicode) -\uFE38 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u23DF\u23DF@2\u23DF@3\u23DF@4\u23DF@5 # ⏟ (MathML 2.0) -\u23B5 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u23B5\u23B5@2\u23B5@3\u23B5@4\u23B5@5 # ⎵ -\u23DD = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u23DD\u23DD@2\u23DD@3\u23DD@4\u23DD@5 # ⏝ (Unicode) -\uFE36 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u23DD\u23DD@2\u23DD@3\u23DD@4\u23DD@5 # ⏝ (MathML 2.0) - -\u005E = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u0302\u0302@2\u0302@3\u0302@4\u0302@5 # circumflex accent, COMBINING CIRCUMFLEX ACCENT -\u02C6 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u0302\u0302@2\u0302@3\u0302@4\u0302@5 # modifier letter circumflex accent, COMBINING CIRCUMFLEX ACCENT -\u007E = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u0303\u0303@2\u0303@3\u0303@4\u0303@5 # ~ tilde, COMBINING TILDE -\u02DC = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u0303\u0303@2\u0303@3\u0303@4\u0303@5 # small tilde, COMBINING TILDE -\u02C7 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u030C\u030C@2\u030C@3\u030C@4\u030C@5 # caron, COMBINING CARON diff --git a/layout/mathml/moz.build b/layout/mathml/moz.build index 62fd09c48938..3b0813ad1de9 100644 --- a/layout/mathml/moz.build +++ b/layout/mathml/moz.build @@ -55,11 +55,9 @@ JAR_MANIFESTS += ['jar.mn'] RESOURCE_FILES.fonts += [ 'mathfont.properties', - 'mathfontAsanaMath.properties', 'mathfontMathJax_Main.properties', 'mathfontStandardSymbolsL.properties', 'mathfontSTIXNonUnicode.properties', - 'mathfontSTIXSize1.properties', 'mathfontSTIXSizeOneSym.properties', 'mathfontUnicode.properties', ] diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index d5f61766e753..87a835c665f4 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -1526,7 +1526,7 @@ pref("intl.hyphenation-alias.no-*", "nb"); pref("intl.hyphenation-alias.nb-*", "nb"); pref("intl.hyphenation-alias.nn-*", "nn"); -pref("font.mathfont-family", "MathJax_Main, STIXNonUnicode, STIXSizeOneSym, STIXSize1, STIXGeneral, Asana Math, Standard Symbols L, DejaVu Sans, Cambria Math"); +pref("font.mathfont-family", "MathJax_Main, STIXNonUnicode, STIXSizeOneSym, STIXGeneral, Asana Math, Standard Symbols L, DejaVu Sans, Cambria Math"); // Some CJK fonts have bad underline offset, their CJK character glyphs are overlapped (or adjoined) to its underline. // These fonts are ignored the underline offset, instead of it, the underline is lowered to bottom of its em descent. @@ -2556,7 +2556,7 @@ pref("font.size.variable.zh-HK", 16); pref("font.size.fixed.zh-HK", 16); // We have special support for Monotype Symbol on Windows. -pref("font.mathfont-family", "MathJax_Main, STIXNonUnicode, STIXSizeOneSym, STIXSize1, STIXGeneral, Asana Math, Symbol, DejaVu Sans, Cambria Math"); +pref("font.mathfont-family", "MathJax_Main, STIXNonUnicode, STIXSizeOneSym, STIXGeneral, Asana Math, Symbol, DejaVu Sans, Cambria Math"); // cleartype settings - false implies default system settings @@ -3088,7 +3088,7 @@ pref("font.size.variable.zh-HK", 15); pref("font.size.fixed.zh-HK", 16); // Apple's Symbol is Unicode so use it -pref("font.mathfont-family", "MathJax_Main, STIXNonUnicode, STIXSizeOneSym, STIXSize1, STIXGeneral, Asana Math, Symbol, DejaVu Sans, Cambria Math"); +pref("font.mathfont-family", "MathJax_Main, STIXNonUnicode, STIXSizeOneSym, STIXGeneral, Asana Math, Symbol, DejaVu Sans, Cambria Math"); // individual font faces to be treated as independent families // names are Postscript names of each face From dd936cd2e4c6880ba5d2eb00957639568bc518c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Wang?= Date: Wed, 23 Apr 2014 06:57:42 -0700 Subject: [PATCH 32/40] Bug 407059 - Part 4: Use gfxHarfbuzzShaper::GetGlyphHAdvance() for math operators. r=jfkthame --- gfx/thebes/gfxFT2FontBase.cpp | 4 +- gfx/thebes/gfxFT2Fonts.cpp | 3 - gfx/thebes/gfxFont.cpp | 23 +++ gfx/thebes/gfxFont.h | 34 +++-- gfx/thebes/gfxHarfBuzzShaper.cpp | 240 ++++++++++++++++--------------- gfx/thebes/gfxHarfBuzzShaper.h | 6 + gfx/thebes/gfxPangoFonts.cpp | 3 - layout/mathml/nsMathMLChar.cpp | 22 ++- 8 files changed, 190 insertions(+), 145 deletions(-) diff --git a/gfx/thebes/gfxFT2FontBase.cpp b/gfx/thebes/gfxFT2FontBase.cpp index 0693b9aff38b..3755b5554bbc 100644 --- a/gfx/thebes/gfxFT2FontBase.cpp +++ b/gfx/thebes/gfxFT2FontBase.cpp @@ -117,7 +117,9 @@ gfxFT2FontBase::GetMetrics() new(&mMetrics) gfxFont::Metrics(); // zero initialize mSpaceGlyph = 0; } else { - gfxFT2LockedFace(this).GetMetrics(&mMetrics, &mSpaceGlyph); + gfxFT2LockedFace face(this); + mFUnitsConvFactor = face.XScale(); + face.GetMetrics(&mMetrics, &mSpaceGlyph); } SanitizeMetrics(&mMetrics, false); diff --git a/gfx/thebes/gfxFT2Fonts.cpp b/gfx/thebes/gfxFT2Fonts.cpp index 6177548985ff..48836fa43b64 100644 --- a/gfx/thebes/gfxFT2Fonts.cpp +++ b/gfx/thebes/gfxFT2Fonts.cpp @@ -426,9 +426,6 @@ gfxFT2Font::ShapeText(gfxContext *aContext, if (!ok && gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript)) { if (!mHarfBuzzShaper) { - gfxFT2LockedFace face(this); - mFUnitsConvFactor = face.XScale(); - mHarfBuzzShaper = new gfxHarfBuzzShaper(this); } ok = mHarfBuzzShaper->ShapeText(aContext, aText, diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index c0aa3bb9c8c4..c4fcb932bf7d 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -23,6 +23,7 @@ #include "gfxTypes.h" #include "gfxContext.h" #include "gfxFontMissingGlyphs.h" +#include "gfxHarfBuzzShaper.h" #include "gfxUserFontSet.h" #include "gfxPlatformFontList.h" #include "gfxScriptItemizer.h" @@ -2027,6 +2028,28 @@ gfxFont::~gfxFont() } } +gfxFloat +gfxFont::GetGlyphHAdvance(gfxContext *aCtx, uint16_t aGID) +{ + if (ProvidesGlyphWidths()) { + return GetGlyphWidth(aCtx, aGID) / 65536.0; + } + if (mFUnitsConvFactor == 0.0f) { + GetMetrics(); + } + NS_ASSERTION(mFUnitsConvFactor > 0.0f, + "missing font unit conversion factor"); + if (!mHarfBuzzShaper) { + mHarfBuzzShaper = new gfxHarfBuzzShaper(this); + } + gfxHarfBuzzShaper* shaper = + static_cast(mHarfBuzzShaper.get()); + if (!shaper->Initialize() || !SetupCairoFont(aCtx)) { + return 0; + } + return shaper->GetGlyphHAdvance(aCtx, aGID) / 65536.0; +} + /*static*/ PLDHashOperator gfxFont::AgeCacheEntry(CacheHashEntry *aEntry, void *aUserData) diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index ac0443178cec..977b72fb72c0 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -43,6 +43,8 @@ class gfxTextRun; class gfxFont; class gfxFontFamily; class gfxFontGroup; +class gfxGraphiteShaper; +class gfxHarfBuzzShaper; class gfxUserFontSet; class gfxUserFontData; class gfxShapedText; @@ -1457,6 +1459,10 @@ protected: /* a SPECIFIC single font family */ class gfxFont { + + friend class gfxHarfBuzzShaper; + friend class gfxGraphiteShaper; + public: nsrefcnt AddRef(void) { NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt"); @@ -1584,19 +1590,8 @@ public: virtual uint32_t GetGlyph(uint32_t unicode, uint32_t variation_selector) { return 0; } - - // subclasses may provide (possibly hinted) glyph widths (in font units); - // if they do not override this, harfbuzz will use unhinted widths - // derived from the font tables - virtual bool ProvidesGlyphWidths() { - return false; - } - - // The return value is interpreted as a horizontal advance in 16.16 fixed - // point format. - virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID) { - return -1; - } + // Return the horizontal advance of a glyph. + gfxFloat GetGlyphHAdvance(gfxContext *aCtx, uint16_t aGID); // Return Azure GlyphRenderingOptions for drawing this font. virtual mozilla::TemporaryRef @@ -1892,6 +1887,19 @@ public: } protected: + // subclasses may provide (possibly hinted) glyph widths (in font units); + // if they do not override this, harfbuzz will use unhinted widths + // derived from the font tables + virtual bool ProvidesGlyphWidths() { + return false; + } + + // The return value is interpreted as a horizontal advance in 16.16 fixed + // point format. + virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID) { + return -1; + } + void AddGlyphChangeObserver(GlyphChangeObserver *aObserver); void RemoveGlyphChangeObserver(GlyphChangeObserver *aObserver); diff --git a/gfx/thebes/gfxHarfBuzzShaper.cpp b/gfx/thebes/gfxHarfBuzzShaper.cpp index 5c4b803490d9..84e4e4c845d3 100644 --- a/gfx/thebes/gfxHarfBuzzShaper.cpp +++ b/gfx/thebes/gfxHarfBuzzShaper.cpp @@ -188,10 +188,6 @@ hb_position_t gfxHarfBuzzShaper::GetGlyphHAdvance(gfxContext *aContext, hb_codepoint_t glyph) const { - if (mUseFontGlyphWidths) { - return mFont->GetGlyphWidth(aContext, glyph); - } - // font did not implement GetHintedGlyphWidth, so get an unhinted value // directly from the font tables @@ -211,13 +207,19 @@ gfxHarfBuzzShaper::GetGlyphHAdvance(gfxContext *aContext, uint16_t(hmtx->metrics[glyph].advanceWidth)); } -static hb_position_t -HBGetGlyphHAdvance(hb_font_t *font, void *font_data, - hb_codepoint_t glyph, void *user_data) +/* static */ +hb_position_t +gfxHarfBuzzShaper::HBGetGlyphHAdvance(hb_font_t *font, void *font_data, + hb_codepoint_t glyph, void *user_data) { const gfxHarfBuzzShaper::FontCallbackData *fcd = static_cast(font_data); - return fcd->mShaper->GetGlyphHAdvance(fcd->mContext, glyph); + gfxFont *gfxfont = fcd->mShaper->GetFont(); + if (gfxfont->ProvidesGlyphWidths()) { + return gfxfont->GetGlyphWidth(fcd->mContext, glyph); + } else { + return fcd->mShaper->GetGlyphHAdvance(fcd->mContext, glyph); + } } static hb_bool_t @@ -817,6 +819,121 @@ static hb_unicode_funcs_t * sHBUnicodeFuncs = nullptr; static const hb_script_t sMathScript = hb_ot_tag_to_script(HB_TAG('m','a','t','h')); +bool +gfxHarfBuzzShaper::Initialize() +{ + if (mInitialized) { + return mHBFont != nullptr; + } + mInitialized = true; + mCallbackData.mShaper = this; + + mUseFontGlyphWidths = mFont->ProvidesGlyphWidths(); + + if (!sHBFontFuncs) { + // static function callback pointers, initialized by the first + // harfbuzz shaper used + sHBFontFuncs = hb_font_funcs_create(); + hb_font_funcs_set_glyph_func(sHBFontFuncs, HBGetGlyph, + nullptr, nullptr); + hb_font_funcs_set_glyph_h_advance_func(sHBFontFuncs, + HBGetGlyphHAdvance, + nullptr, nullptr); + hb_font_funcs_set_glyph_contour_point_func(sHBFontFuncs, + HBGetContourPoint, + nullptr, nullptr); + hb_font_funcs_set_glyph_h_kerning_func(sHBFontFuncs, + HBGetHKerning, + nullptr, nullptr); + + sHBUnicodeFuncs = + hb_unicode_funcs_create(hb_unicode_funcs_get_empty()); + hb_unicode_funcs_set_mirroring_func(sHBUnicodeFuncs, + HBGetMirroring, + nullptr, nullptr); + hb_unicode_funcs_set_script_func(sHBUnicodeFuncs, HBGetScript, + nullptr, nullptr); + hb_unicode_funcs_set_general_category_func(sHBUnicodeFuncs, + HBGetGeneralCategory, + nullptr, nullptr); + hb_unicode_funcs_set_combining_class_func(sHBUnicodeFuncs, + HBGetCombiningClass, + nullptr, nullptr); + hb_unicode_funcs_set_eastasian_width_func(sHBUnicodeFuncs, + HBGetEastAsianWidth, + nullptr, nullptr); + hb_unicode_funcs_set_compose_func(sHBUnicodeFuncs, + HBUnicodeCompose, + nullptr, nullptr); + hb_unicode_funcs_set_decompose_func(sHBUnicodeFuncs, + HBUnicodeDecompose, + nullptr, nullptr); + } + + gfxFontEntry *entry = mFont->GetFontEntry(); + if (!mUseFontGetGlyph) { + // get the cmap table and find offset to our subtable + mCmapTable = entry->GetFontTable(TRUETYPE_TAG('c','m','a','p')); + if (!mCmapTable) { + NS_WARNING("failed to load cmap, glyphs will be missing"); + return false; + } + uint32_t len; + const uint8_t* data = (const uint8_t*)hb_blob_get_data(mCmapTable, &len); + bool symbol; + mCmapFormat = gfxFontUtils:: + FindPreferredSubtable(data, len, + &mSubtableOffset, &mUVSTableOffset, + &symbol); + if (mCmapFormat <= 0) { + return false; + } + } + + if (!mUseFontGlyphWidths) { + // if font doesn't implement GetGlyphWidth, we will be reading + // the hmtx table directly; + // read mNumLongMetrics from hhea table without caching its blob, + // and preload/cache the hmtx table + gfxFontEntry::AutoTable hheaTable(entry, TRUETYPE_TAG('h','h','e','a')); + if (hheaTable) { + uint32_t len; + const HMetricsHeader* hhea = + reinterpret_cast + (hb_blob_get_data(hheaTable, &len)); + if (len >= sizeof(HMetricsHeader)) { + mNumLongMetrics = hhea->numberOfHMetrics; + if (mNumLongMetrics > 0 && + int16_t(hhea->metricDataFormat) == 0) { + // no point reading hmtx if number of entries is zero! + // in that case, we won't be able to use this font + // (this method will return FALSE below if mHmtx is null) + mHmtxTable = + entry->GetFontTable(TRUETYPE_TAG('h','m','t','x')); + if (hb_blob_get_length(mHmtxTable) < + mNumLongMetrics * sizeof(HLongMetric)) { + // hmtx table is not large enough for the claimed + // number of entries: invalid, do not use. + hb_blob_destroy(mHmtxTable); + mHmtxTable = nullptr; + } + } + } + } + if (!mHmtxTable) { + return false; + } + } + + mHBFont = hb_font_create(mHBFace); + hb_font_set_funcs(mHBFont, sHBFontFuncs, &mCallbackData, nullptr); + hb_font_set_ppem(mHBFont, mFont->GetAdjustedSize(), mFont->GetAdjustedSize()); + uint32_t scale = FloatToFixed(mFont->GetAdjustedSize()); // 16.16 fixed-point + hb_font_set_scale(mHBFont, scale, scale); + + return true; +} + bool gfxHarfBuzzShaper::ShapeText(gfxContext *aContext, const char16_t *aText, @@ -831,112 +948,8 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext, } mCallbackData.mContext = aContext; - gfxFontEntry *entry = mFont->GetFontEntry(); - if (!mInitialized) { - mInitialized = true; - mCallbackData.mShaper = this; - - mUseFontGlyphWidths = mFont->ProvidesGlyphWidths(); - - if (!sHBFontFuncs) { - // static function callback pointers, initialized by the first - // harfbuzz shaper used - sHBFontFuncs = hb_font_funcs_create(); - hb_font_funcs_set_glyph_func(sHBFontFuncs, HBGetGlyph, - nullptr, nullptr); - hb_font_funcs_set_glyph_h_advance_func(sHBFontFuncs, - HBGetGlyphHAdvance, - nullptr, nullptr); - hb_font_funcs_set_glyph_contour_point_func(sHBFontFuncs, - HBGetContourPoint, - nullptr, nullptr); - hb_font_funcs_set_glyph_h_kerning_func(sHBFontFuncs, - HBGetHKerning, - nullptr, nullptr); - - sHBUnicodeFuncs = - hb_unicode_funcs_create(hb_unicode_funcs_get_empty()); - hb_unicode_funcs_set_mirroring_func(sHBUnicodeFuncs, - HBGetMirroring, - nullptr, nullptr); - hb_unicode_funcs_set_script_func(sHBUnicodeFuncs, HBGetScript, - nullptr, nullptr); - hb_unicode_funcs_set_general_category_func(sHBUnicodeFuncs, - HBGetGeneralCategory, - nullptr, nullptr); - hb_unicode_funcs_set_combining_class_func(sHBUnicodeFuncs, - HBGetCombiningClass, - nullptr, nullptr); - hb_unicode_funcs_set_eastasian_width_func(sHBUnicodeFuncs, - HBGetEastAsianWidth, - nullptr, nullptr); - hb_unicode_funcs_set_compose_func(sHBUnicodeFuncs, - HBUnicodeCompose, - nullptr, nullptr); - hb_unicode_funcs_set_decompose_func(sHBUnicodeFuncs, - HBUnicodeDecompose, - nullptr, nullptr); - } - - if (!mUseFontGetGlyph) { - // get the cmap table and find offset to our subtable - mCmapTable = entry->GetFontTable(TRUETYPE_TAG('c','m','a','p')); - if (!mCmapTable) { - NS_WARNING("failed to load cmap, glyphs will be missing"); - return false; - } - uint32_t len; - const uint8_t* data = (const uint8_t*)hb_blob_get_data(mCmapTable, &len); - bool symbol; - mCmapFormat = gfxFontUtils:: - FindPreferredSubtable(data, len, - &mSubtableOffset, &mUVSTableOffset, - &symbol); - } - - if (!mUseFontGlyphWidths) { - // if font doesn't implement GetGlyphWidth, we will be reading - // the hmtx table directly; - // read mNumLongMetrics from hhea table without caching its blob, - // and preload/cache the hmtx table - gfxFontEntry::AutoTable hheaTable(entry, TRUETYPE_TAG('h','h','e','a')); - if (hheaTable) { - uint32_t len; - const HMetricsHeader* hhea = - reinterpret_cast - (hb_blob_get_data(hheaTable, &len)); - if (len >= sizeof(HMetricsHeader)) { - mNumLongMetrics = hhea->numberOfHMetrics; - if (mNumLongMetrics > 0 && - int16_t(hhea->metricDataFormat) == 0) { - // no point reading hmtx if number of entries is zero! - // in that case, we won't be able to use this font - // (this method will return FALSE below if mHmtx is null) - mHmtxTable = - entry->GetFontTable(TRUETYPE_TAG('h','m','t','x')); - if (hb_blob_get_length(mHmtxTable) < - mNumLongMetrics * sizeof(HLongMetric)) { - // hmtx table is not large enough for the claimed - // number of entries: invalid, do not use. - hb_blob_destroy(mHmtxTable); - mHmtxTable = nullptr; - } - } - } - } - } - - mHBFont = hb_font_create(mHBFace); - hb_font_set_funcs(mHBFont, sHBFontFuncs, &mCallbackData, nullptr); - hb_font_set_ppem(mHBFont, mFont->GetAdjustedSize(), mFont->GetAdjustedSize()); - uint32_t scale = FloatToFixed(mFont->GetAdjustedSize()); // 16.16 fixed-point - hb_font_set_scale(mHBFont, scale, scale); - } - - if ((!mUseFontGetGlyph && mCmapFormat <= 0) || - (!mUseFontGlyphWidths && !mHmtxTable)) { - // unable to shape with this font + if (!Initialize()) { return false; } @@ -945,6 +958,7 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext, nsAutoTArray features; nsDataHashtable mergedFeatures; + gfxFontEntry *entry = mFont->GetFontEntry(); if (MergeFontFeatures(style, entry->mFeatureSettings, aShapedText->DisableLigatures(), diff --git a/gfx/thebes/gfxHarfBuzzShaper.h b/gfx/thebes/gfxHarfBuzzShaper.h index f5325f77291c..f82f70d75e6d 100644 --- a/gfx/thebes/gfxHarfBuzzShaper.h +++ b/gfx/thebes/gfxHarfBuzzShaper.h @@ -24,6 +24,7 @@ public: gfxContext *mContext; }; + bool Initialize(); virtual bool ShapeText(gfxContext *aContext, const char16_t *aText, uint32_t aOffset, @@ -42,6 +43,11 @@ public: hb_position_t GetGlyphHAdvance(gfxContext *aContext, hb_codepoint_t glyph) const; + // get harfbuzz horizontal advance in 16.16 fixed point format. + static hb_position_t + HBGetGlyphHAdvance(hb_font_t *font, void *font_data, + hb_codepoint_t glyph, void *user_data); + hb_position_t GetHKerning(uint16_t aFirstGlyph, uint16_t aSecondGlyph) const; diff --git a/gfx/thebes/gfxPangoFonts.cpp b/gfx/thebes/gfxPangoFonts.cpp index ff2654c28bc3..d1f0a54a356d 100644 --- a/gfx/thebes/gfxPangoFonts.cpp +++ b/gfx/thebes/gfxPangoFonts.cpp @@ -1624,10 +1624,7 @@ gfxFcFont::ShapeText(gfxContext *aContext, if (!ok) { if (!mHarfBuzzShaper) { - gfxFT2LockedFace face(this); mHarfBuzzShaper = new gfxHarfBuzzShaper(this); - // Used by gfxHarfBuzzShaper, currently only for kerning - mFUnitsConvFactor = face.XScale(); } ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength, aScript, aShapedText); diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp index 7ea753a9527f..176265f6cce3 100644 --- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -542,9 +542,10 @@ nsOpenTypeTable::MakeTextRun(gfxContext* aThebesContext, false); gfxTextRun::DetailedGlyph detailedGlyph; detailedGlyph.mGlyphID = aGlyph.glyphID; - // We set the advance width to zero and this will be fixed in MeasureTextRun. - // XXXfredw: We should use gfxHarfbuzzShaper::GetGlyphHAdvance() - detailedGlyph.mAdvance = 0; + detailedGlyph.mAdvance = + NSToCoordRound(aAppUnitsPerDevPixel * + aFontGroup->GetFontAt(0)-> + GetGlyphHAdvance(aThebesContext, aGlyph.glyphID)); detailedGlyph.mXOffset = detailedGlyph.mYOffset = 0; gfxShapedText::CompressedGlyph g; g.SetComplex(true, true, 1); @@ -1153,11 +1154,6 @@ MeasureTextRun(gfxContext* aThebesContext, gfxTextRun* aTextRun) bm.ascent = NSToCoordCeil(-metrics.mBoundingBox.Y()); bm.descent = NSToCoordCeil(metrics.mBoundingBox.YMost()); bm.width = NSToCoordRound(metrics.mAdvanceWidth); - if (bm.width == 0) { - // The advance width was not set in nsGlyphTable::MakeTextRun, so we use - // the right bearing instead. - bm.width = bm.rightBearing; - } return bm; } @@ -1296,10 +1292,12 @@ StretchEnumContext::TryVariants(nsGlyphTable* aGlyphTable, if (ch.IsGlyphID()) { gfxFont* mathFont = aFontGroup->get()->GetFontAt(0); if (mathFont->GetFontEntry()->TryGetMathTable(mathFont)) { - // MeasureTextRun has set the advance width to the right bearing. We now - // subtract the italic correction, so that nsMathMLmmultiscripts will - // place the scripts correctly. - // Note that STIX-Word does not provide italic corrections + // MeasureTextRun should have set the advance width to the right + // bearing for OpenType MATH fonts. We now subtract the italic + // correction, so that nsMathMLmmultiscripts will place the scripts + // correctly. + // Note that STIX-Word does not provide italic corrections but its + // advance widths do not match right bearings. // (http://sourceforge.net/p/stixfonts/tracking/50/) gfxFloat italicCorrection; if (mathFont->GetFontEntry()-> From 5ddbcc0e325a8f82d06054d2531bddb73b443f43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Wang?= Date: Wed, 23 Apr 2014 06:57:43 -0700 Subject: [PATCH 33/40] Bug 407059 - Part 5: Add reftest. r=karlt --- layout/reftests/fonts/math/README | 6 + layout/reftests/fonts/math/generate.py | 231 ++++++++++++++++++ layout/reftests/fonts/math/stretchy.otf | Bin 0 -> 3336 bytes .../mathml/opentype-stretchy-ref.html | 73 ++++++ layout/reftests/mathml/opentype-stretchy.html | 73 ++++++ layout/reftests/mathml/reftest.list | 1 + 6 files changed, 384 insertions(+) create mode 100644 layout/reftests/fonts/math/README create mode 100644 layout/reftests/fonts/math/generate.py create mode 100644 layout/reftests/fonts/math/stretchy.otf create mode 100644 layout/reftests/mathml/opentype-stretchy-ref.html create mode 100644 layout/reftests/mathml/opentype-stretchy.html diff --git a/layout/reftests/fonts/math/README b/layout/reftests/fonts/math/README new file mode 100644 index 000000000000..fa5b1344d4fb --- /dev/null +++ b/layout/reftests/fonts/math/README @@ -0,0 +1,6 @@ +The fonts in this directory are autogenerated with FontForge using the Python +script generate.py. See the comments in that file for more information on how +to run the script. + +These fonts are intended to test the The MATH table and OpenType Features used +in MathML. See layout/reftests/mathml/ diff --git a/layout/reftests/fonts/math/generate.py b/layout/reftests/fonts/math/generate.py new file mode 100644 index 000000000000..d0562cf39bd5 --- /dev/null +++ b/layout/reftests/fonts/math/generate.py @@ -0,0 +1,231 @@ +#!/usr/bin/python +# vim: set shiftwidth=4 tabstop=8 autoindent expandtab: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# For general fontforge documentation, see: +# http://fontforge.sourceforge.net/ +# For fontforge scripting documentation, see: +# http://fontforge.sourceforge.net/scripting-tutorial.html +# http://fontforge.sourceforge.net/scripting.html +# and most importantly: +# http://fontforge.sourceforge.net/python.html + +# To install what you need, on Ubuntu, +# sudo apt-get install python-fontforge + +from __future__ import print_function +import fontforge + +em = 1000 + +def newMathFont(aName): + print("Generating %s.otf..." % aName, end="") + mathFont = fontforge.font() + mathFont.fontname = aName + mathFont.familyname = aName + mathFont.fullname = aName + mathFont.copyright = "Copyright (c) 2014 Mozilla Corporation" + mathFont.encoding = "UnicodeFull" + + # Create a space character. Also force the creation of some MATH subtables + # so that OTS will not reject the MATH table. + g = mathFont.createChar(ord(" "), "space") + g.width = em + g.italicCorrection = 0 + g.topaccent = 0 + g.mathKern.bottomLeft = tuple([(0,0)]) + g.mathKern.bottomRight = tuple([(0,0)]) + g.mathKern.topLeft = tuple([(0,0)]) + g.mathKern.topRight = tuple([(0,0)]) + mathFont[ord(" ")].horizontalVariants = "space" + mathFont[ord(" ")].verticalVariants = "space" + return mathFont + +def saveMathFont(aFont): + aFont.em = em + aFont.ascent = aFont.descent = em/2 + aFont.hhea_ascent = aFont.os2_typoascent = aFont.os2_winascent = em/2 + aFont.descent = aFont.hhea_descent = em/2 + aFont.os2_typodescent = aFont.os2_windescent = em/2 + aFont.hhea_ascent_add = aFont.hhea_descent_add = 0 + aFont.os2_typoascent_add = aFont.os2_typodescent_add = 0 + aFont.os2_winascent_add = aFont.os2_windescent_add = 0 + aFont.os2_use_typo_metrics = True + aFont.generate(aFont.fontname + ".otf") + print(" done.") + +################################################################################ +# Glyph variants and constructions +f = newMathFont("stretchy") +nvariants = 3 + +# Draw boxes for the size variants and glues +for i in range(0, nvariants): + s = em * (i + 1) + + g = f.createChar(-1, "h%d" % i) + p = g.glyphPen() + p.moveTo(0, -em) + p.lineTo(0, em) + p.lineTo(s, em) + p.lineTo(s, -em) + p.closePath() + g.width = s + + g = f.createChar(-1, "v%d" % i) + p = g.glyphPen() + p.moveTo(0, 0) + p.lineTo(0, s) + p.lineTo(2 * em, s) + p.lineTo(2 * em, 0) + p.closePath(); + g.width = 2 * em + +# Draw some pieces for stretchy operators +s = em * nvariants + +g = f.createChar(-1, "left") +p = g.glyphPen() +p.moveTo(0, -2 * em) +p.lineTo(0, 2 * em) +p.lineTo(s, em) +p.lineTo(s, -em) +p.closePath(); +g.width = s + +g = f.createChar(-1, "right") +p = g.glyphPen() +p.moveTo(0, -em) +p.lineTo(0, em) +p.lineTo(s, 2 * em) +p.lineTo(s, -2 * em) +p.closePath(); +g.width = s + +g = f.createChar(-1, "hmid") +p = g.glyphPen() +p.moveTo(0, -em) +p.lineTo(0, em) +p.lineTo(s, 2 * em) +p.lineTo(2 * s, em) +p.lineTo(2 * s, -em) +p.lineTo(s, -2 * em) +p.closePath(); +g.width = 2 * s + +g = f.createChar(-1, "bottom") +p = g.glyphPen() +p.moveTo(0, 0) +p.lineTo(0, s) +p.lineTo(2 * em, s) +p.lineTo(4 * em, 0) +p.closePath(); +g.width = 4 * em + +g = f.createChar(-1, "top") +p = g.glyphPen() +p.moveTo(0, 0) +p.lineTo(4 * em, 0) +p.lineTo(2 * em, -s) +p.lineTo(0, -s) +p.closePath(); +g.width = 4 * em + +g = f.createChar(-1, "vmid") +p = g.glyphPen() +p.moveTo(0, s) +p.lineTo(2 * em, s) +p.lineTo(4 * em, 0) +p.lineTo(2 * em, -s) +p.lineTo(0, -s) +p.closePath(); +g.width = 3 * em + +# Create small rectangle of various size for some exotic arrows that are +# unlikely to be stretchable with standard fonts. +hstretchy = [ + 0x219C, # leftwards wave arrow + 0x219D, # rightwards wave arrow + 0x219E, # leftwards two headed arrow + 0x21A0, # rightwards two headed arrow + 0x21A2 # leftwards arrow with tail +] +vstretchy = [ + 0x219F, # upwards two headed arrow + 0x21A1, # downwards two headed arrow + 0x21A5, # upwards arrow from bar + 0x21A7, # downwards arrow from bar + 0x21A8 # up down arrow with base +] +for i in range(0, 1 + nvariants + 1): + s = (i + 1) * em/10 + + g = f.createChar(hstretchy[i]) + p = g.glyphPen() + p.moveTo(0, -em/10) + p.lineTo(0, em/10) + p.lineTo(s, em/10) + p.lineTo(s, -em/10) + p.closePath() + g.width = s + + g = f.createChar(vstretchy[i]) + p = g.glyphPen() + p.moveTo(0, 0) + p.lineTo(0, s) + p.lineTo(2 * em/10, s) + p.lineTo(2 * em/10, 0) + p.closePath(); + g.width = 2 * em/10 + +# hstretchy[0] and vstretchy[0] have all the variants and the components. The others only have one of them. +s = em * nvariants + +f[hstretchy[0]].horizontalVariants = "uni219C h0 h1 h2" +f[hstretchy[0]].horizontalComponents = (("left", False, 0, 0, s), \ +("h2", True, 0, 0, s), ("hmid", False, 0, 0, 2 * s), ("h2", True, 0, 0, s), \ +("right", False, 0, 0, s)) + +f[hstretchy[1]].horizontalVariants = "uni219D h0" +f[hstretchy[2]].horizontalVariants = "uni219E h1" +f[hstretchy[3]].horizontalVariants = "uni21A0 h2" +f[hstretchy[4]].horizontalVariants = "uni21A2 h2" +f[hstretchy[4]].horizontalComponents = f[hstretchy[0]].horizontalComponents + +f[vstretchy[0]].verticalVariants = "uni219F v0 v1 v2" +f[vstretchy[0]].verticalComponents = (("bottom", False, 0, 0, s), \ +("v2", True, 0, 0, s), ("vmid", False, 0, 0, 2 * s), ("v2", True, 0, 0, s), \ +("top", False, 0, 0, s)) + +f[vstretchy[1]].verticalVariants = "uni21A1 v0" +f[vstretchy[2]].verticalVariants = "uni21A5 v1" +f[vstretchy[3]].verticalVariants = "uni21A7 v2" +f[vstretchy[4]].verticalVariants = "uni21A8" +f[vstretchy[4]].verticalComponents = f[vstretchy[0]].verticalComponents + +################################################################################ +# Testing DisplayOperatorMinHeight +f.math.DisplayOperatorMinHeight = 8 * em +largeop = [0x2A1B, 0x2A1C] # integral with overbar/underbar + +# Draw boxes of size 1, 2, 7, 8, 9em. +for i in [1, 2, 7, 8, 9]: + s = em * i + if i == 1 or i == 2: + g = f.createChar(largeop[i-1]) + else: + g = f.createChar(-1, "L%d" % i) + p = g.glyphPen() + p.moveTo(0, 0) + p.lineTo(0, s) + p.lineTo(s, s) + p.lineTo(s, 0) + p.closePath(); + g.width = s + +f[largeop[0]].verticalVariants = "uni2A1B L7 L8 L9" +f[largeop[1]].verticalVariants = "uni2A1C L8" + +saveMathFont(f) diff --git a/layout/reftests/fonts/math/stretchy.otf b/layout/reftests/fonts/math/stretchy.otf new file mode 100644 index 0000000000000000000000000000000000000000..f192de346316ee35c7da99356a83361b28ed7b61 GIT binary patch literal 3336 zcmds4ZERcR6@HF=?R?mEl76$?lA9&8X-k4_6+%Cd(q=^ck*qK(6e^41ByJr@V&gcW zMec+EL05NcDW&^jtV3eU541^B#fL;DYy5yAB+3sY5LHzKg6_u@O$*q#kno&)uhS+- zsO;x%?)#o|p7Wgdy!ZX`n>~B??m+;Lz>9EqPmk69#c40#3j@Y&Jw1E-9%y@c3aCi~ zF#C4y-TmpQvF)^v0p998cij|i_{Wa*fLQe3H#izkcTes)Pv48g29k;RP;+#&oxayt zZb=fj;b8MmsL!&rCP%XefA#cR5Tyd8`jds9*6sKl0q-RucxU41$Q3!eyQQtAjdnFWit=HM%*rhGDgM=3 z*4on5&pLqpU=71&`k4QyN5A5jBjq9@!uCAybG+O~Te+`d*s=g?lj-ELYdg2guwdDF zL-@-={`L5=s|)-4q^mOto^y3CS~2752C8MftNTzdce=Wtc$PCNMh$cIvN*b+9uuza zK@cZg-HY9L!PO16v(nXlu;eCJ_Y)sLH&RIB5Hc9X0VI*-H?(088!4j*BZ4i|`p9~i zj1m6DX=_x5aazY2GfZs^=uV{%WrhzVvsT;SMk^YQY_a-M4-b!w#I5dBCY{Q}v%@L! z#u<`9g7qL%9wLy5WL+jGze zI?>MVw=aAMdQxNAo>b;Q!isi;t!-8%FV#qA`<8a?@^^OcZsyJ~pYy>Md!R$4J<&f4 zxI2*<=Qmp6aHJy~4ij10xvM_bo=2Ta?nQT|V>&ywZJ>)XXs>buR`c`CFEmeWGUw-s zTFuYW`tzp7`T6;eF6_TBbYbwl|F|vC?L6YYdU00J#ZpuKpFi$yo_|cwnQuP=!+?m? zRMrA`3J5w%btv5;rA|-jR&QyIkvC^|n=Ng8eWrBRnLxcMxdszIG>yP=T(2?JsKaWW zF|F9lTw6JRy|@ee5W~GZMFzO8_v3yp<#8_g98c&+@i?Bqi#UtdCdP)Nk*(d1_>m)S zcSMgZc7`1haYWP+H#?#;p2?&hnn(|g4U8ug+8Np9i0))~GMtP|Mv~FV=tyFJ*501U z(cz(iR5qI$&8E_mGB&zmsR>_wtw$RRn!gX?9yi4X8^d@Xfi zNmO=8zl_P_Y~WRSS1x(Ho^_s1&z)xZcz(Kgcv_~Xi-l?L^y*S;@uRO={nMBKx~h1% zSh#$+Dm2#+GE4ItiZRL0csCd`#n=Xa$To{H+QnEgb~)w`nP0x)fCU8$1PlI9en#?S z<;j|{N#)H-+F&qGjCn%zE->77%Ew*G5mJsQrErB(&{ob&E&!$0rN9vd<{I+loUkx; zIakij<@}*9@@CaJ(Tbo|>u|htITDCD3=J}95h{flGN&#lhC~J}ZKV8}L!s9Uyh1V; zIpeg4G?+*sI<&R&XB0{+=hR7NIp-tl#Lf|{J40}epjjWNpo{qxfAw}vVK5@kMx6|K z##L|6KcqOfTGhEKC%NVz!!R$MxB@y+j9BsCyxG{#?l$&ocN_cl{bY(0y5_^Y+0;c( zQWp2ENh|}DJ z_g(`}&p>kRv#_F9!j|IduapXhwyXlaeviNoo_MP%TPd9%5~0*{@M^1-RuIdv7S~rA z`IdCzR?18A7Nh-G&!5y?ygBW&Pt2d;C{E%}_#6I?w;1cNr(nRxpW{03ztB+iE>;9y zrO$&Z{L{u%uaS1!r+TeCWpk$N>;{62`$6M9Xl&XEvqi_)gJo<-?MjZb%;8~<5V`gA zEq8NxnL{y+F_=Srs{5HkIcKR?%jYhi*ITTiAAwg`t#CELb*imNFT(Vm?C@0i-{V#; zw6omR#GWfB-xZ8=xhUWFk8|eR$8oRWS`TopmvM&tEFRuv3~JT9nZv%x4>1{6wcO~+ n6RxCR@k&u{)j20dWu@r&sjgCsj$Pdur>Nc759l7#{{p@N?dN~* literal 0 HcmV?d00001 diff --git a/layout/reftests/mathml/opentype-stretchy-ref.html b/layout/reftests/mathml/opentype-stretchy-ref.html new file mode 100644 index 000000000000..3507990af5e7 --- /dev/null +++ b/layout/reftests/mathml/opentype-stretchy-ref.html @@ -0,0 +1,73 @@ + + + + Open Type MATH - stretchy operator + + + + + + + +

+ + + + + + + + +

+ +

+ + + + +

+ + +

+ + + +

+ + + diff --git a/layout/reftests/mathml/opentype-stretchy.html b/layout/reftests/mathml/opentype-stretchy.html new file mode 100644 index 000000000000..572fa7844110 --- /dev/null +++ b/layout/reftests/mathml/opentype-stretchy.html @@ -0,0 +1,73 @@ + + + + Open Type MATH - stretchy operator + + + + + + + +

+ + + + + + + + +

+ +

+ + + + +

+ + +

+ + + +

+ + + diff --git a/layout/reftests/mathml/reftest.list b/layout/reftests/mathml/reftest.list index d97069a538f1..ffa9a3c73907 100644 --- a/layout/reftests/mathml/reftest.list +++ b/layout/reftests/mathml/reftest.list @@ -152,6 +152,7 @@ skip-if(B2G) == maction-dynamic-3.html maction-dynamic-3-ref.html # bug 773482 == whitespace-trim-3.html whitespace-trim-3-ref.html fails == whitespace-trim-4.html whitespace-trim-4-ref.html # Bug 787215 == whitespace-trim-5.html whitespace-trim-5-ref.html +fails-if(winWidget&&!d2d) == opentype-stretchy.html opentype-stretchy-ref.html == operator-1.xhtml operator-1-ref.xhtml == scriptshift-1.xhtml scriptshift-1-ref.xhtml == number-size-1.xhtml number-size-1-ref.xhtml From 20617bb17d1ae28df0ebda02a8a405b9ae21395d Mon Sep 17 00:00:00 2001 From: Marco Castelluccio Date: Wed, 23 Apr 2014 06:57:43 -0700 Subject: [PATCH 34/40] Bug 981251 - Test app uninstallation. r=myk --HG-- rename : toolkit/webapps/tests/test_hosted.xul => toolkit/webapps/tests/test_hosted_uninstall.xul rename : toolkit/webapps/tests/test_packaged.xul => toolkit/webapps/tests/test_packaged_uninstall.xul --- toolkit/webapps/tests/chrome.ini | 2 + toolkit/webapps/tests/head.js | 33 ++ .../webapps/tests/test_hosted_uninstall.xul | 269 +++++++++++++++++ .../webapps/tests/test_packaged_uninstall.xul | 281 ++++++++++++++++++ 4 files changed, 585 insertions(+) create mode 100644 toolkit/webapps/tests/test_hosted_uninstall.xul create mode 100644 toolkit/webapps/tests/test_packaged_uninstall.xul diff --git a/toolkit/webapps/tests/chrome.ini b/toolkit/webapps/tests/chrome.ini index e5547e96103f..ea90292157b0 100644 --- a/toolkit/webapps/tests/chrome.ini +++ b/toolkit/webapps/tests/chrome.ini @@ -15,3 +15,5 @@ skip-if = asan skip-if = asan [test_packaged_launch_no_registry.xul] skip-if = asan +[test_hosted_uninstall.xul] +[test_packaged_uninstall.xul] diff --git a/toolkit/webapps/tests/head.js b/toolkit/webapps/tests/head.js index 2ca323f546d7..259d68077330 100644 --- a/toolkit/webapps/tests/head.js +++ b/toolkit/webapps/tests/head.js @@ -44,6 +44,39 @@ function checkDateHigherThan(files, date) { }); } +function dirContainsOnly(dir, expectedFiles) { + return Task.spawn(function*() { + let iterator = new OS.File.DirectoryIterator(dir); + + let entries; + try { + entries = yield iterator.nextBatch(); + } finally { + iterator.close(); + } + + let ret = true; + + // Find unexpected files + for each (let {path} in entries) { + if (expectedFiles.indexOf(path) == -1) { + info("Unexpected file: " + path); + ret = false; + } + } + + // Find missing files + for each (let expectedPath in expectedFiles) { + if (entries.findIndex(({path}) => path == expectedPath) == -1) { + info("Missing file: " + expectedPath); + ret = false; + } + } + + return ret; + }); +} + function wait(time) { let deferred = Promise.defer(); diff --git a/toolkit/webapps/tests/test_hosted_uninstall.xul b/toolkit/webapps/tests/test_hosted_uninstall.xul new file mode 100644 index 000000000000..3009517c79f7 --- /dev/null +++ b/toolkit/webapps/tests/test_hosted_uninstall.xul @@ -0,0 +1,269 @@ + + + + + + + + diff --git a/toolkit/webapps/tests/test_packaged_uninstall.xul b/toolkit/webapps/tests/test_packaged_uninstall.xul new file mode 100644 index 000000000000..a7d630320e0d --- /dev/null +++ b/toolkit/webapps/tests/test_packaged_uninstall.xul @@ -0,0 +1,281 @@ + + + + + + + + From fcb1c588efd344cf5ecd14b2af8636e887985798 Mon Sep 17 00:00:00 2001 From: Henri Sivonen Date: Tue, 22 Apr 2014 12:35:44 +0300 Subject: [PATCH 35/40] Bug 999349 - Add "DO NOT USE" annotation to nsIPlatformCharset. r=emk --- content/base/src/nsDOMFile.cpp | 1 - dom/file/ArchiveZipEvent.cpp | 2 -- dom/workers/RuntimeService.cpp | 1 - intl/locale/public/nsIPlatformCharset.h | 7 +++++++ 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/content/base/src/nsDOMFile.cpp b/content/base/src/nsDOMFile.cpp index 28c098c897d1..ac120b4c3e87 100644 --- a/content/base/src/nsDOMFile.cpp +++ b/content/base/src/nsDOMFile.cpp @@ -20,7 +20,6 @@ #include "nsIIPCSerializableInputStream.h" #include "nsIMemoryReporter.h" #include "nsIMIMEService.h" -#include "nsIPlatformCharset.h" #include "nsISeekableStream.h" #include "nsIUnicharInputStream.h" #include "nsIUnicodeDecoder.h" diff --git a/dom/file/ArchiveZipEvent.cpp b/dom/file/ArchiveZipEvent.cpp index 2492322bb602..7586874c18ac 100644 --- a/dom/file/ArchiveZipEvent.cpp +++ b/dom/file/ArchiveZipEvent.cpp @@ -8,8 +8,6 @@ #include "ArchiveZipFile.h" #include "nsContentUtils.h" -#include "nsIPlatformCharset.h" -#include "nsNativeCharsetUtils.h" #include "nsCExternalHandlerService.h" using namespace mozilla::dom; diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index f8b3231fccbd..7190a195e264 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -12,7 +12,6 @@ #include "nsIDOMChromeWindow.h" #include "nsIEffectiveTLDService.h" #include "nsIObserverService.h" -#include "nsIPlatformCharset.h" #include "nsIPrincipal.h" #include "nsIScriptContext.h" #include "nsIScriptSecurityManager.h" diff --git a/intl/locale/public/nsIPlatformCharset.h b/intl/locale/public/nsIPlatformCharset.h index 24a37bcfe0a3..1cc889bb6718 100644 --- a/intl/locale/public/nsIPlatformCharset.h +++ b/intl/locale/public/nsIPlatformCharset.h @@ -34,6 +34,13 @@ typedef enum { kPlatformCharsetSel_PlainTextInFile = 7 } nsPlatformCharsetSel; +/** + * DO NOT ADD NEW USES OF THIS INTERFACE! + * Removal is https://bugzilla.mozilla.org/show_bug.cgi?id=943272 + * + * Instead, use UTF-16 APIs on Windows and UTF-8 APIs everywhere else. + * Assume plain text files are UTF-8. + */ class nsIPlatformCharset : public nsISupports { public: From 9e083a5d8a86ee126a44989496424d1fef0d0a88 Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Wed, 23 Apr 2014 14:55:58 +0300 Subject: [PATCH 36/40] Bug 990725 - Rename ErrorEvent.column to .colno to match spec change; r=smaug --- dom/base/nsJSEnvironment.cpp | 2 +- dom/events/JSEventHandler.cpp | 2 +- dom/events/test/test_error_events.html | 2 +- dom/webidl/ErrorEvent.webidl | 4 ++-- dom/workers/WorkerPrivate.cpp | 2 +- dom/workers/test/test_sharedWorker.html | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 7ac2cbba7d6a..09938d181820 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -482,7 +482,7 @@ public: if (sameOrigin) { init.mMessage = mErrorMsg; init.mLineno = mLineNumber; - init.mColumn = mColumn; + init.mColno = mColumn; init.mError = mError; } else { NS_WARNING("Not same origin error!"); diff --git a/dom/events/JSEventHandler.cpp b/dom/events/JSEventHandler.cpp index 9e77f924ad7c..37eeccc3f48e 100644 --- a/dom/events/JSEventHandler.cpp +++ b/dom/events/JSEventHandler.cpp @@ -142,7 +142,7 @@ JSEventHandler::HandleEvent(nsIDOMEvent* aEvent) lineNumber.Value() = scriptEvent->Lineno(); columnNumber.Construct(); - columnNumber.Value() = scriptEvent->Column(); + columnNumber.Value() = scriptEvent->Colno(); ThreadsafeAutoJSContext cx; error.Construct(cx); diff --git a/dom/events/test/test_error_events.html b/dom/events/test/test_error_events.html index 8f8abc0ce4b0..da52df1a81b0 100644 --- a/dom/events/test/test_error_events.html +++ b/dom/events/test/test_error_events.html @@ -37,7 +37,7 @@ [ "Callback message", msg, "Error: hello" ], [ "Event error-object", errorEvent.error, thrown], [ "Callback error-object", error, thrown ], - [ "Event column", errorEvent.column, 0 ], // Sadly not correct right now + [ "Event column", errorEvent.colno, 0 ], // Sadly not correct right now [ "Callback column", column, 0 ] ]); diff --git a/dom/webidl/ErrorEvent.webidl b/dom/webidl/ErrorEvent.webidl index 3349078ba0af..2e7c000ff406 100644 --- a/dom/webidl/ErrorEvent.webidl +++ b/dom/webidl/ErrorEvent.webidl @@ -9,7 +9,7 @@ interface ErrorEvent : Event readonly attribute DOMString message; readonly attribute DOMString filename; readonly attribute unsigned long lineno; - readonly attribute unsigned long column; + readonly attribute unsigned long colno; readonly attribute any error; }; @@ -18,6 +18,6 @@ dictionary ErrorEventInit : EventInit DOMString message = ""; DOMString filename = ""; unsigned long lineno = 0; - unsigned long column = 0; + unsigned long colno = 0; any error = null; }; diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index c83822edd7e1..47a9e943a3a9 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -3147,7 +3147,7 @@ WorkerPrivateParent::BroadcastErrorToSharedWorkers( errorInit.mMessage = aMessage; errorInit.mFilename = aFilename; errorInit.mLineno = aLineNumber; - errorInit.mColumn = aColumnNumber; + errorInit.mColno = aColumnNumber; nsRefPtr errorEvent = ErrorEvent::Constructor(sharedWorker, NS_LITERAL_STRING("error"), diff --git a/dom/workers/test/test_sharedWorker.html b/dom/workers/test/test_sharedWorker.html index 79e197c0afb1..38b65f6453fd 100644 --- a/dom/workers/test/test_sharedWorker.html +++ b/dom/workers/test/test_sharedWorker.html @@ -57,7 +57,7 @@ is(event.message, "Error: " + sentMessage, "Got correct error"); is(event.filename, errorFilename, "Got correct filename"); is(event.lineno, errorLine, "Got correct lineno"); - is(event.column, errorColumn, "Got correct column"); + is(event.colno, errorColumn, "Got correct column"); ok(receivedMessage !== undefined, "Got message already"); ok(receivedError === undefined, "Haven't gotten error yet"); receivedError = event.message; From 08d9f8a751e380a20312488b47b790188ce1942e Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Wed, 23 Apr 2014 08:42:50 -0600 Subject: [PATCH 37/40] Bug 967704 - Update reftest manifests for Android 2.3; r=me --- layout/reftests/first-letter/reftest.list | 2 +- layout/reftests/font-face/reftest.list | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/layout/reftests/first-letter/reftest.list b/layout/reftests/first-letter/reftest.list index 020f020314a5..85b9be6dbd63 100644 --- a/layout/reftests/first-letter/reftest.list +++ b/layout/reftests/first-letter/reftest.list @@ -35,7 +35,7 @@ random-if(d2d) == dynamic-2.html dynamic-2-ref.html != 229764-1.html 229764-ref.html == 229764-2.html 229764-ref.html == 329069-1.html 329069-1-ref.html -== 329069-2.html 329069-2-ref.html +fails-if(Android&&AndroidVersion==10) == 329069-2.html 329069-2-ref.html # Bug 999139 == 329069-3.html 329069-3-ref.html == 329069-4.html 329069-4-ref.html fails-if(!cocoaWidget) == 329069-5.html 329069-5-ref.html # bug 603710 diff --git a/layout/reftests/font-face/reftest.list b/layout/reftests/font-face/reftest.list index 3263f7e40747..2148bac4a7a8 100644 --- a/layout/reftests/font-face/reftest.list +++ b/layout/reftests/font-face/reftest.list @@ -148,8 +148,8 @@ skip-if(B2G) HTTP(..) == missing-names.html missing-names-ref.html # bug 773482 # Tests for bug 670900 - handling of 404 (not found) error in @font-face URL # (using Chunkfive font data returned from a .sjs file) HTTP(..) == font-error-404-1.html font-error-404-1-ref.html # HTTP status 404, don't load -skip-if(B2G) fails-if(Android&&AndroidVersion==17) HTTP(..) == font-error-404-2.html font-error-404-2-ref.html # HTTP status 200, load # bug 773482 -fails-if(Android&&AndroidVersion==17) HTTP(..) != font-error-404-1.html font-error-404-2.html # sanity-check that the results differ +skip-if(B2G) fails-if(Android&&(AndroidVersion==10||AndroidVersion==17)) HTTP(..) == font-error-404-2.html font-error-404-2-ref.html # HTTP status 200, load # bug 773482 +fails-if(Android&&(AndroidVersion==10||AndroidVersion==17)) HTTP(..) != font-error-404-1.html font-error-404-2.html # sanity-check that the results differ # Font load redirection HTTP(..) == font-redirect.html order-1-ref.html From c71089545f94f2429fce2e441d7886887beecb50 Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Wed, 23 Apr 2014 08:42:51 -0600 Subject: [PATCH 38/40] Bug 997991 - Use default httpd path for robocop, mochitest-remote test targets; r=jmaher --- testing/testsuite-targets.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/testing/testsuite-targets.mk b/testing/testsuite-targets.mk index 5f30a9bc278b..e786ba629f0b 100644 --- a/testing/testsuite-targets.mk +++ b/testing/testsuite-targets.mk @@ -58,7 +58,7 @@ RUN_MOCHITEST_REMOTE = \ $(PYTHON) _tests/testing/mochitest/runtestsremote.py --autorun --close-when-done \ --console-level=INFO --log-file=./$@.log --file-level=INFO $(DM_FLAGS) --dm_trans=$(DM_TRANS) \ --app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \ - --testing-modules-dir=$(abspath _tests/modules) --httpd-path=. \ + --testing-modules-dir=$(abspath _tests/modules) \ $(SYMBOLS_PATH) $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS) RUN_MOCHITEST_ROBOCOP = \ @@ -69,7 +69,6 @@ RUN_MOCHITEST_ROBOCOP = \ --robocop-ini=$(DEPTH)/build/mobile/robocop/robocop.ini \ --console-level=INFO --log-file=./$@.log --file-level=INFO $(DM_FLAGS) --dm_trans=$(DM_TRANS) \ --app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \ - --httpd-path=. \ $(SYMBOLS_PATH) $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS) ifndef NO_FAIL_ON_TEST_ERRORS From 7555d00e896a86006ee5f781dedccc18e6d79282 Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Wed, 23 Apr 2014 17:17:29 +0200 Subject: [PATCH 39/40] Bug 995934 - IonMonkey: Remove branch out of hot code in negative zero test, r=bbouvier --- .../jit/shared/CodeGenerator-x86-shared.cpp | 32 ++++++------ .../jit/shared/MacroAssembler-x86-shared.cpp | 42 ++++++++++++++++ js/src/jit/shared/MacroAssembler-x86-shared.h | 49 +++++-------------- js/src/jit/x64/MacroAssembler-x64.cpp | 16 ------ js/src/jit/x64/MacroAssembler-x64.h | 3 -- js/src/jit/x86/MacroAssembler-x86.cpp | 41 ---------------- js/src/jit/x86/MacroAssembler-x86.h | 3 -- 7 files changed, 71 insertions(+), 115 deletions(-) diff --git a/js/src/jit/shared/CodeGenerator-x86-shared.cpp b/js/src/jit/shared/CodeGenerator-x86-shared.cpp index 27a04ae398cc..675d61691637 100644 --- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp @@ -1558,10 +1558,12 @@ CodeGeneratorX86Shared::visitFloor(LFloor *lir) FloatRegister scratch = ScratchFloatReg; Register output = ToRegister(lir->output()); + Label bailout; + if (AssemblerX86Shared::HasSSE41()) { // Bail on negative-zero. - Assembler::Condition bailCond = masm.testNegativeZero(input, output); - if (!bailoutIf(bailCond, lir->snapshot())) + masm.branchNegativeZero(input, output, &bailout); + if (!bailoutFrom(&bailout, lir->snapshot())) return false; // Round toward -Infinity. @@ -1579,8 +1581,8 @@ CodeGeneratorX86Shared::visitFloor(LFloor *lir) masm.branchDouble(Assembler::DoubleLessThan, input, scratch, &negative); // Bail on negative-zero. - Assembler::Condition bailCond = masm.testNegativeZero(input, output); - if (!bailoutIf(bailCond, lir->snapshot())) + masm.branchNegativeZero(input, output, &bailout); + if (!bailoutFrom(&bailout, lir->snapshot())) return false; // Input is non-negative, so truncation correctly rounds. @@ -1625,10 +1627,12 @@ CodeGeneratorX86Shared::visitFloorF(LFloorF *lir) FloatRegister scratch = ScratchFloatReg; Register output = ToRegister(lir->output()); + Label bailout; + if (AssemblerX86Shared::HasSSE41()) { // Bail on negative-zero. - Assembler::Condition bailCond = masm.testNegativeZeroFloat32(input, output); - if (!bailoutIf(bailCond, lir->snapshot())) + masm.branchNegativeZeroFloat32(input, output, &bailout); + if (!bailoutFrom(&bailout, lir->snapshot())) return false; // Round toward -Infinity. @@ -1646,8 +1650,8 @@ CodeGeneratorX86Shared::visitFloorF(LFloorF *lir) masm.branchFloat(Assembler::DoubleLessThan, input, scratch, &negative); // Bail on negative-zero. - Assembler::Condition bailCond = masm.testNegativeZeroFloat32(input, output); - if (!bailoutIf(bailCond, lir->snapshot())) + masm.branchNegativeZeroFloat32(input, output, &bailout); + if (!bailoutFrom(&bailout, lir->snapshot())) return false; // Input is non-negative, so truncation correctly rounds. @@ -1693,7 +1697,7 @@ CodeGeneratorX86Shared::visitRound(LRound *lir) FloatRegister scratch = ScratchFloatReg; Register output = ToRegister(lir->output()); - Label negative, end; + Label negative, end, bailout; // Load 0.5 in the temp register. masm.loadConstantDouble(0.5, temp); @@ -1703,8 +1707,8 @@ CodeGeneratorX86Shared::visitRound(LRound *lir) masm.branchDouble(Assembler::DoubleLessThan, input, scratch, &negative); // Bail on negative-zero. - Assembler::Condition bailCond = masm.testNegativeZero(input, output); - if (!bailoutIf(bailCond, lir->snapshot())) + masm.branchNegativeZero(input, output, &bailout); + if (!bailoutFrom(&bailout, lir->snapshot())) return false; // Input is non-negative. Add 0.5 and truncate, rounding down. Note that we @@ -1781,7 +1785,7 @@ CodeGeneratorX86Shared::visitRoundF(LRoundF *lir) FloatRegister scratch = ScratchFloatReg; Register output = ToRegister(lir->output()); - Label negative, end; + Label negative, end, bailout; // Load 0.5 in the temp register. masm.loadConstantFloat32(0.5f, temp); @@ -1791,8 +1795,8 @@ CodeGeneratorX86Shared::visitRoundF(LRoundF *lir) masm.branchFloat(Assembler::DoubleLessThan, input, scratch, &negative); // Bail on negative-zero. - Assembler::Condition bailCond = masm.testNegativeZeroFloat32(input, output); - if (!bailoutIf(bailCond, lir->snapshot())) + masm.branchNegativeZeroFloat32(input, output, &bailout); + if (!bailoutFrom(&bailout, lir->snapshot())) return false; // Input is non-negative. Add 0.5 and truncate, rounding down. Note that we diff --git a/js/src/jit/shared/MacroAssembler-x86-shared.cpp b/js/src/jit/shared/MacroAssembler-x86-shared.cpp index 8353878d327b..c07b2292e3ad 100644 --- a/js/src/jit/shared/MacroAssembler-x86-shared.cpp +++ b/js/src/jit/shared/MacroAssembler-x86-shared.cpp @@ -154,3 +154,45 @@ MacroAssemblerX86Shared::buildOOLFakeExitFrame(void *fakeReturnAddr) Push(ImmPtr(fakeReturnAddr)); return true; } + +void +MacroAssemblerX86Shared::branchNegativeZero(const FloatRegister ®, + const Register &scratch, + Label *label) +{ + // Determines whether the low double contained in the XMM register reg + // is equal to -0.0. + +#if defined(JS_CODEGEN_X86) + Label nonZero; + + // Compare to zero. Lets through {0, -0}. + xorpd(ScratchFloatReg, ScratchFloatReg); + + // If reg is non-zero, jump to nonZero. + branchDouble(DoubleNotEqual, reg, ScratchFloatReg, &nonZero); + + // Input register is either zero or negative zero. Retrieve sign of input. + movmskpd(reg, scratch); + + // If reg is 1 or 3, input is negative zero. + // If reg is 0 or 2, input is a normal zero. + branchTest32(NonZero, scratch, Imm32(1), label); + + bind(&nonZero); +#elif defined(JS_CODEGEN_X64) + movq(reg, scratch); + cmpq(scratch, Imm32(1)); + j(Overflow, label); +#endif +} + +void +MacroAssemblerX86Shared::branchNegativeZeroFloat32(const FloatRegister ®, + const Register &scratch, + Label *label) +{ + movd(reg, scratch); + cmpl(scratch, Imm32(1)); + j(Overflow, label); +} diff --git a/js/src/jit/shared/MacroAssembler-x86-shared.h b/js/src/jit/shared/MacroAssembler-x86-shared.h index e000d39dca29..319dd6986365 100644 --- a/js/src/jit/shared/MacroAssembler-x86-shared.h +++ b/js/src/jit/shared/MacroAssembler-x86-shared.h @@ -90,6 +90,9 @@ class MacroAssemblerX86Shared : public Assembler j(ConditionFromDoubleCondition(cond), label); } + void branchNegativeZero(const FloatRegister ®, const Register &scratch, Label *label); + void branchNegativeZeroFloat32(const FloatRegister ®, const Register &scratch, Label *label); + void move32(const Imm32 &imm, const Register &dest) { // Use the ImmWord version of mov to register, which has special // optimizations. Casting to uint32_t here ensures that the value @@ -519,31 +522,16 @@ class MacroAssemblerX86Shared : public Assembler void convertDoubleToInt32(FloatRegister src, Register dest, Label *fail, bool negativeZeroCheck = true) { + // Check for -0.0 + if (negativeZeroCheck) + branchNegativeZero(src, dest, fail); + cvttsd2si(src, dest); cvtsi2sd(dest, ScratchFloatReg); ucomisd(src, ScratchFloatReg); j(Assembler::Parity, fail); j(Assembler::NotEqual, fail); - // Check for -0 - if (negativeZeroCheck) { - Label notZero; - testl(dest, dest); - j(Assembler::NonZero, ¬Zero); - - if (Assembler::HasSSE41()) { - ptest(src, src); - j(Assembler::NonZero, fail); - } else { - // bit 0 = sign of low double - // bit 1 = sign of high double - movmskpd(src, dest); - andl(Imm32(1), dest); - j(Assembler::NonZero, fail); - } - - bind(¬Zero); - } } // Checks whether a float32 is representable as a 32-bit integer. If so, the @@ -552,30 +540,15 @@ class MacroAssemblerX86Shared : public Assembler void convertFloat32ToInt32(FloatRegister src, Register dest, Label *fail, bool negativeZeroCheck = true) { + // Check for -0.0 + if (negativeZeroCheck) + branchNegativeZeroFloat32(src, dest, fail); + cvttss2si(src, dest); convertInt32ToFloat32(dest, ScratchFloatReg); ucomiss(src, ScratchFloatReg); j(Assembler::Parity, fail); j(Assembler::NotEqual, fail); - - // Check for -0 - if (negativeZeroCheck) { - Label notZero; - branchTest32(Assembler::NonZero, dest, dest, ¬Zero); - - if (Assembler::HasSSE41()) { - ptest(src, src); - j(Assembler::NonZero, fail); - } else { - // bit 0 = sign of low float - // bits 1 to 3 = signs of higher floats - movmskps(src, dest); - andl(Imm32(1), dest); - j(Assembler::NonZero, fail); - } - - bind(¬Zero); - } } void clampIntToUint8(Register reg) { diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp index 449a62e79659..9a9f995b7c3a 100644 --- a/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -367,22 +367,6 @@ MacroAssemblerX64::handleFailureWithHandlerTail() jmp(Operand(rsp, offsetof(ResumeFromException, target))); } -Assembler::Condition -MacroAssemblerX64::testNegativeZero(const FloatRegister ®, const Register &scratch) -{ - movq(reg, scratch); - cmpq(scratch, Imm32(1)); - return Overflow; -} - -Assembler::Condition -MacroAssemblerX64::testNegativeZeroFloat32(const FloatRegister ®, const Register &scratch) -{ - movd(reg, scratch); - cmpl(scratch, Imm32(1)); - return Overflow; -} - #ifdef JSGC_GENERATIONAL void diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index c239b3895196..6ccf900673bc 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -507,9 +507,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared emitSet(cond, dest); } - Condition testNegativeZero(const FloatRegister ®, const Register &scratch); - Condition testNegativeZeroFloat32(const FloatRegister ®, const Register &scratch); - ///////////////////////////////////////////////////////////////// // Common interface. ///////////////////////////////////////////////////////////////// diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index b366813479ef..d36f4d32c5c2 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -387,47 +387,6 @@ MacroAssemblerX86::branchTestValue(Condition cond, const ValueOperand &value, co } } -Assembler::Condition -MacroAssemblerX86::testNegativeZero(const FloatRegister ®, const Register &scratch) -{ - // Determines whether the single double contained in the XMM register reg - // is equal to double-precision -0. - - Label nonZero; - - // Compare to zero. Lets through {0, -0}. - xorpd(ScratchFloatReg, ScratchFloatReg); - - // If reg is non-zero, jump to nonZero. - // Sets ZF=0 and PF=0. - branchDouble(DoubleNotEqual, reg, ScratchFloatReg, &nonZero); - - // Input register is either zero or negative zero. Retrieve sign of input. - movmskpd(reg, scratch); - - // If reg is 1 or 3, input is negative zero. - // If reg is 0 or 2, input is a normal zero. - // So the following test will set PF=1 for negative zero. - orl(Imm32(2), scratch); - - bind(&nonZero); - - // Here we need to be able to test if the input is a negative zero. - // - branchDouble joins here for non-zero values in which case it sets - // ZF=0 and PF=0. In that case the test should fail. - // - orl sets PF=1 on negative zero and PF=0 otherwise - // => So testing PF=1 will return if input is negative zero or not. - return Parity; -} - -Assembler::Condition -MacroAssemblerX86::testNegativeZeroFloat32(const FloatRegister ®, const Register &scratch) -{ - movd(reg, scratch); - cmpl(scratch, Imm32(1)); - return Overflow; -} - #ifdef JSGC_GENERATIONAL void diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index bcba6d478b48..ab591173701d 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -529,9 +529,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared emitSet(cond, dest); } - Condition testNegativeZero(const FloatRegister ®, const Register &scratch); - Condition testNegativeZeroFloat32(const FloatRegister ®, const Register &scratch); - ///////////////////////////////////////////////////////////////// // Common interface. ///////////////////////////////////////////////////////////////// From e519ca57d3a393461a65e5a1c393d83249906c4d Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Wed, 23 Apr 2014 13:18:44 -0400 Subject: [PATCH 40/40] Backed out changeset a7289f22cafd (bug 981251) for WinXP test_bug343416.xul perma-fail. CLOSED TREE --- toolkit/webapps/tests/chrome.ini | 2 - toolkit/webapps/tests/head.js | 33 -- .../webapps/tests/test_hosted_uninstall.xul | 269 ----------------- .../webapps/tests/test_packaged_uninstall.xul | 281 ------------------ 4 files changed, 585 deletions(-) delete mode 100644 toolkit/webapps/tests/test_hosted_uninstall.xul delete mode 100644 toolkit/webapps/tests/test_packaged_uninstall.xul diff --git a/toolkit/webapps/tests/chrome.ini b/toolkit/webapps/tests/chrome.ini index ea90292157b0..e5547e96103f 100644 --- a/toolkit/webapps/tests/chrome.ini +++ b/toolkit/webapps/tests/chrome.ini @@ -15,5 +15,3 @@ skip-if = asan skip-if = asan [test_packaged_launch_no_registry.xul] skip-if = asan -[test_hosted_uninstall.xul] -[test_packaged_uninstall.xul] diff --git a/toolkit/webapps/tests/head.js b/toolkit/webapps/tests/head.js index 259d68077330..2ca323f546d7 100644 --- a/toolkit/webapps/tests/head.js +++ b/toolkit/webapps/tests/head.js @@ -44,39 +44,6 @@ function checkDateHigherThan(files, date) { }); } -function dirContainsOnly(dir, expectedFiles) { - return Task.spawn(function*() { - let iterator = new OS.File.DirectoryIterator(dir); - - let entries; - try { - entries = yield iterator.nextBatch(); - } finally { - iterator.close(); - } - - let ret = true; - - // Find unexpected files - for each (let {path} in entries) { - if (expectedFiles.indexOf(path) == -1) { - info("Unexpected file: " + path); - ret = false; - } - } - - // Find missing files - for each (let expectedPath in expectedFiles) { - if (entries.findIndex(({path}) => path == expectedPath) == -1) { - info("Missing file: " + expectedPath); - ret = false; - } - } - - return ret; - }); -} - function wait(time) { let deferred = Promise.defer(); diff --git a/toolkit/webapps/tests/test_hosted_uninstall.xul b/toolkit/webapps/tests/test_hosted_uninstall.xul deleted file mode 100644 index 3009517c79f7..000000000000 --- a/toolkit/webapps/tests/test_hosted_uninstall.xul +++ /dev/null @@ -1,269 +0,0 @@ - - - - - - - - diff --git a/toolkit/webapps/tests/test_packaged_uninstall.xul b/toolkit/webapps/tests/test_packaged_uninstall.xul deleted file mode 100644 index a7d630320e0d..000000000000 --- a/toolkit/webapps/tests/test_packaged_uninstall.xul +++ /dev/null @@ -1,281 +0,0 @@ - - - - - - - -