From 235f1f55edf8318d72de452ebe20395bf904ebfa Mon Sep 17 00:00:00 2001 From: JW Wang Date: Fri, 14 Apr 2017 14:52:14 +0800 Subject: [PATCH 01/65] Bug 1356506 - change the type of MediaData::mTimecode to TimeUnit since int64_t is ambiguous. r=gerald MozReview-Commit-ID: 7dO5OOUuORz --HG-- extra : rebase_source : 1c1c020700d9180ef9f85d7e2e679f498ab71fce extra : intermediate-source : d173c820bef7a113e28e9732c42e8c1af36160ab extra : source : 04c08a780526ca3a5ac4d1a6f9b7ae30d9957e92 --- dom/media/ADTSDemuxer.cpp | 2 +- dom/media/MP3Demuxer.cpp | 2 +- dom/media/MediaData.cpp | 2 +- dom/media/MediaData.h | 5 +-- dom/media/MediaFormatReader.cpp | 2 +- dom/media/flac/FlacDemuxer.cpp | 2 +- dom/media/fmp4/MP4Demuxer.cpp | 4 +- dom/media/gtest/TestMP4Demuxer.cpp | 2 +- dom/media/ipc/VideoDecoderChild.cpp | 2 +- dom/media/ipc/VideoDecoderParent.cpp | 4 +- dom/media/mediasource/TrackBuffersManager.cpp | 42 ++++++++----------- dom/media/ogg/OggCodecState.cpp | 2 +- .../platforms/agnostic/NullDecoderModule.cpp | 2 +- .../platforms/agnostic/TheoraDecoder.cpp | 5 ++- dom/media/platforms/agnostic/VPXDecoder.cpp | 4 +- .../platforms/agnostic/VorbisDecoder.cpp | 5 ++- dom/media/platforms/apple/AppleVTDecoder.cpp | 2 +- dom/media/platforms/apple/AppleVTDecoder.h | 2 +- .../platforms/ffmpeg/FFmpegVideoDecoder.cpp | 9 ++-- dom/media/wave/WaveDemuxer.cpp | 2 +- dom/media/webm/WebMDemuxer.cpp | 10 ++--- media/libstagefright/binding/Index.cpp | 2 +- 22 files changed, 53 insertions(+), 61 deletions(-) diff --git a/dom/media/ADTSDemuxer.cpp b/dom/media/ADTSDemuxer.cpp index 045c83da1a66..2b1ab372595d 100644 --- a/dom/media/ADTSDemuxer.cpp +++ b/dom/media/ADTSDemuxer.cpp @@ -754,7 +754,7 @@ ADTSTrackDemuxer::GetNextFrame(const adts::Frame& aFrame) frame->mTime = Duration(mFrameIndex - 1).ToMicroseconds(); frame->mDuration = Duration(1); - frame->mTimecode = frame->mTime; + frame->mTimecode = media::TimeUnit::FromMicroseconds(frame->mTime); frame->mKeyframe = true; MOZ_ASSERT(frame->mTime >= 0); diff --git a/dom/media/MP3Demuxer.cpp b/dom/media/MP3Demuxer.cpp index ba3e2150ac40..1bf9e416da98 100644 --- a/dom/media/MP3Demuxer.cpp +++ b/dom/media/MP3Demuxer.cpp @@ -606,7 +606,7 @@ MP3TrackDemuxer::GetNextFrame(const MediaByteRange& aRange) frame->mTime = Duration(mFrameIndex - 1).ToMicroseconds(); frame->mDuration = Duration(1); - frame->mTimecode = frame->mTime; + frame->mTimecode = media::TimeUnit::FromMicroseconds(frame->mTime); frame->mKeyframe = true; MOZ_ASSERT(frame->mTime >= 0); diff --git a/dom/media/MediaData.cpp b/dom/media/MediaData.cpp index 9f5c6edd161c..fa40620a6e35 100644 --- a/dom/media/MediaData.cpp +++ b/dom/media/MediaData.cpp @@ -176,7 +176,7 @@ VideoData::VideoData(int64_t aOffset, { MOZ_ASSERT(!mDuration.IsNegative(), "Frame must have non-negative duration."); mKeyframe = aKeyframe; - mTimecode = aTimecode; + mTimecode = TimeUnit::FromMicroseconds(aTimecode); } VideoData::~VideoData() diff --git a/dom/media/MediaData.h b/dom/media/MediaData.h index 3bd9ea600e09..63d4829cae4f 100644 --- a/dom/media/MediaData.h +++ b/dom/media/MediaData.h @@ -295,7 +295,7 @@ public: : mType(aType) , mOffset(aOffset) , mTime(aTimestamp) - , mTimecode(aTimestamp) + , mTimecode(media::TimeUnit::FromMicroseconds(aTimestamp)) , mDuration(media::TimeUnit::FromMicroseconds(aDuration)) , mFrames(aFrames) , mKeyframe(false) @@ -313,7 +313,7 @@ public: // Codec specific internal time code. For Ogg based codecs this is the // granulepos. - int64_t mTimecode; + media::TimeUnit mTimecode; // Duration of sample, in microseconds. media::TimeUnit mDuration; @@ -353,7 +353,6 @@ protected: : mType(aType) , mOffset(0) , mTime(0) - , mTimecode(0) , mFrames(aFrames) , mKeyframe(false) { diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index e79882bfaf23..0f02cc4297e3 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -2023,7 +2023,7 @@ MediaFormatReader::HandleDemuxedSamples( } LOGV("Input:%" PRId64 " (dts:%" PRId64 " kf:%d)", - sample->mTime, sample->mTimecode, sample->mKeyframe); + sample->mTime, sample->mTimecode.ToMicroseconds(), sample->mKeyframe); decoder.mNumSamplesInput++; decoder.mSizeOfQueue++; if (aTrack == TrackInfo::kVideoTrack) { diff --git a/dom/media/flac/FlacDemuxer.cpp b/dom/media/flac/FlacDemuxer.cpp index fd840a551921..48c02dbbba47 100644 --- a/dom/media/flac/FlacDemuxer.cpp +++ b/dom/media/flac/FlacDemuxer.cpp @@ -982,7 +982,7 @@ FlacTrackDemuxer::GetNextFrame(const flac::Frame& aFrame) frame->mTime = aFrame.Time().ToMicroseconds(); frame->mDuration = aFrame.Duration(); - frame->mTimecode = frame->mTime; + frame->mTimecode = TimeUnit::FromMicroseconds(frame->mTime); frame->mOffset = aFrame.Offset(); frame->mKeyframe = true; diff --git a/dom/media/fmp4/MP4Demuxer.cpp b/dom/media/fmp4/MP4Demuxer.cpp index 93f4a6724bfb..fe10a21c0436 100644 --- a/dom/media/fmp4/MP4Demuxer.cpp +++ b/dom/media/fmp4/MP4Demuxer.cpp @@ -463,7 +463,7 @@ MP4TrackDemuxer::GetNextSample() " dts:%" PRId64, keyframe ? "" : "non-", sample->mTime, sample->mDuration.ToMicroseconds(), - sample->mTimecode) + sample->mTimecode.ToMicroseconds()) .get()); sample->mKeyframe = keyframe; } @@ -474,7 +474,7 @@ MP4TrackDemuxer::GetNextSample() nsPrintfCString("Invalid H264 frame @ pts:%" PRId64 " dur:%" PRId64 " dts:%" PRId64, sample->mTime, sample->mDuration.ToMicroseconds(), - sample->mTimecode) + sample->mTimecode.ToMicroseconds()) .get()); // We could reject the sample now, however demuxer errors are fatal. // So we keep the invalid frame, relying on the H264 decoder to diff --git a/dom/media/gtest/TestMP4Demuxer.cpp b/dom/media/gtest/TestMP4Demuxer.cpp index f1210fde77af..381e3079c796 100644 --- a/dom/media/gtest/TestMP4Demuxer.cpp +++ b/dom/media/gtest/TestMP4Demuxer.cpp @@ -125,7 +125,7 @@ public: for (uint32_t i = 0; i < (binding->mSamples.Length() - 1); i++) { EXPECT_LT(binding->mSamples[i]->mTimecode, binding->mSamples[i + 1]->mTimecode); if (binding->mSamples[i]->mKeyframe) { - binding->mKeyFrameTimecodes.AppendElement(binding->mSamples[i]->mTimecode); + binding->mKeyFrameTimecodes.AppendElement(binding->mSamples[i]->mTimecode.ToMicroseconds()); } } binding->mCheckTrackSamples.Resolve(true, __func__); diff --git a/dom/media/ipc/VideoDecoderChild.cpp b/dom/media/ipc/VideoDecoderChild.cpp index e710e27894cc..b925b322d80d 100644 --- a/dom/media/ipc/VideoDecoderChild.cpp +++ b/dom/media/ipc/VideoDecoderChild.cpp @@ -231,7 +231,7 @@ VideoDecoderChild::Decode(MediaRawData* aSample) MediaRawDataIPDL sample(MediaDataIPDL(aSample->mOffset, aSample->mTime, - aSample->mTimecode, + aSample->mTimecode.ToMicroseconds(), aSample->mDuration.ToMicroseconds(), aSample->mFrames, aSample->mKeyframe), diff --git a/dom/media/ipc/VideoDecoderParent.cpp b/dom/media/ipc/VideoDecoderParent.cpp index 2751f5b0d207..85372044477a 100644 --- a/dom/media/ipc/VideoDecoderParent.cpp +++ b/dom/media/ipc/VideoDecoderParent.cpp @@ -138,7 +138,7 @@ VideoDecoderParent::RecvInput(const MediaRawDataIPDL& aData) } data->mOffset = aData.base().offset(); data->mTime = aData.base().time(); - data->mTimecode = aData.base().timecode(); + data->mTimecode = media::TimeUnit::FromMicroseconds(aData.base().timecode()); data->mDuration = media::TimeUnit::FromMicroseconds(aData.base().duration()); data->mKeyframe = aData.base().keyframe(); @@ -191,7 +191,7 @@ VideoDecoderParent::ProcessDecodedData( } VideoDataIPDL output( - MediaDataIPDL(data->mOffset, data->mTime, data->mTimecode, + MediaDataIPDL(data->mOffset, data->mTime, data->mTimecode.ToMicroseconds(), data->mDuration.ToMicroseconds(), data->mFrames, data->mKeyframe), video->mDisplay, diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index 3b723ec23f58..3e9b28659325 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -1490,7 +1490,7 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData) aTrackData.mInfo->mMimeType.get(), sample->mTime, sample->GetEndTime().ToMicroseconds(), - sample->mTimecode, + sample->mTimecode.ToMicroseconds(), sample->mDuration.ToMicroseconds(), sample->mKeyframe); @@ -1525,7 +1525,7 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData) // 4. If timestampOffset is not 0, then run the following steps: TimeUnit sampleTime = TimeUnit::FromMicroseconds(sample->mTime); - TimeUnit sampleTimecode = TimeUnit::FromMicroseconds(sample->mTimecode); + TimeUnit sampleTimecode = sample->mTimecode; TimeUnit sampleDuration = sample->mDuration; TimeUnit timestampOffset = mSourceBufferAttributes->GetTimestampOffset(); @@ -1619,7 +1619,7 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData) samplesRange += sampleInterval; sizeNewSamples += sample->ComputedSizeOfIncludingThis(); sample->mTime = sampleInterval.mStart.ToMicroseconds(); - sample->mTimecode = decodeTimestamp.ToMicroseconds(); + sample->mTimecode = decodeTimestamp; sample->mTrackInfo = trackBuffer.mLastInfo; samples.AppendElement(sample); @@ -2170,7 +2170,7 @@ TrackBuffersManager::Seek(TrackInfo::TrackType aTrack, break; } if (sample->mKeyframe) { - lastKeyFrameTimecode = TimeUnit::FromMicroseconds(sample->mTimecode); + lastKeyFrameTimecode = sample->mTimecode; lastKeyFrameTime = Some(sampleTime); lastKeyFrameIndex = i; } @@ -2242,8 +2242,7 @@ TrackBuffersManager::SkipToNextRandomAccessPoint(TrackInfo::TrackType aTrack, aFound = true; break; } - nextSampleTimecode = - TimeUnit::FromMicroseconds(sample->mTimecode) + sample->mDuration; + nextSampleTimecode = sample->mTimecode + sample->mDuration; nextSampleTime = sample->GetEndTime(); parsed++; } @@ -2252,8 +2251,7 @@ TrackBuffersManager::SkipToNextRandomAccessPoint(TrackInfo::TrackType aTrack, // SkipToNextRandomAccessPoint will not count again the parsed sample as // skipped. if (aFound) { - trackData.mNextSampleTimecode = - TimeUnit::FromMicroseconds(track[i]->mTimecode); + trackData.mNextSampleTimecode = track[i]->mTimecode; trackData.mNextSampleTime = TimeUnit::FromMicroseconds(track[i]->mTime); trackData.mNextGetSampleIndex = Some(i); @@ -2263,8 +2261,7 @@ TrackBuffersManager::SkipToNextRandomAccessPoint(TrackInfo::TrackType aTrack, for (int j = i - 1; j >= originalPos; j--) { const RefPtr& sample = track[j]; if (sample->mKeyframe) { - trackData.mNextSampleTimecode = - TimeUnit::FromMicroseconds(sample->mTimecode); + trackData.mNextSampleTimecode = sample->mTimecode; trackData.mNextSampleTime = TimeUnit::FromMicroseconds(sample->mTime); trackData.mNextGetSampleIndex = Some(uint32_t(j)); // We are unable to skip to a keyframe past aTimeThreshold, however @@ -2300,7 +2297,7 @@ TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack, } const RefPtr& sample = track[aIndex]; - if (!aIndex || sample->mTimecode <= (aExpectedDts + aFuzz).ToMicroseconds() || + if (!aIndex || sample->mTimecode <= aExpectedDts + aFuzz || sample->mTime <= (aExpectedPts + aFuzz).ToMicroseconds()) { return sample; } @@ -2358,8 +2355,7 @@ TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack, } trackData.mNextGetSampleIndex.ref()++; // Estimate decode timestamp and timestamp of the next sample. - TimeUnit nextSampleTimecode = - TimeUnit::FromMicroseconds(sample->mTimecode) + sample->mDuration; + TimeUnit nextSampleTimecode = sample->mTimecode + sample->mDuration; TimeUnit nextSampleTime = sample->GetEndTime(); const MediaRawData* nextSample = GetSample(aTrack, @@ -2369,8 +2365,7 @@ TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack, aFuzz); if (nextSample) { // We have a valid next sample, can use exact values. - trackData.mNextSampleTimecode = - TimeUnit::FromMicroseconds(nextSample->mTimecode); + trackData.mNextSampleTimecode = nextSample->mTimecode; trackData.mNextSampleTime = TimeUnit::FromMicroseconds(nextSample->mTime); } else { @@ -2383,8 +2378,7 @@ TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack, } if (trackData.mNextSampleTimecode > - TimeUnit::FromMicroseconds(track.LastElement()->mTimecode) - + track.LastElement()->mDuration) { + track.LastElement()->mTimecode + track.LastElement()->mDuration) { // The next element is past our last sample. We're done. trackData.mNextGetSampleIndex = Some(uint32_t(track.Length())); aResult = NS_ERROR_DOM_MEDIA_END_OF_STREAM; @@ -2415,8 +2409,7 @@ TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack, UpdateEvictionIndex(trackData, i); trackData.mNextGetSampleIndex = Some(uint32_t(pos)+1); - trackData.mNextSampleTimecode = - TimeUnit::FromMicroseconds(sample->mTimecode) + sample->mDuration; + trackData.mNextSampleTimecode = sample->mTimecode + sample->mDuration; trackData.mNextSampleTime = sample->GetEndTime(); aResult = NS_OK; return p.forget(); @@ -2434,8 +2427,8 @@ TrackBuffersManager::FindCurrentPosition(TrackInfo::TrackType aTrack, for (uint32_t i = 0; i < track.Length(); i++) { const RefPtr& sample = track[i]; TimeInterval sampleInterval{ - TimeUnit::FromMicroseconds(sample->mTimecode), - TimeUnit::FromMicroseconds(sample->mTimecode) + sample->mDuration}; + sample->mTimecode, + sample->mTimecode + sample->mDuration}; if (sampleInterval.ContainsStrict(trackData.mNextSampleTimecode)) { return i; @@ -2450,8 +2443,8 @@ TrackBuffersManager::FindCurrentPosition(TrackInfo::TrackType aTrack, for (uint32_t i = 0; i < track.Length(); i++) { const RefPtr& sample = track[i]; TimeInterval sampleInterval{ - TimeUnit::FromMicroseconds(sample->mTimecode), - TimeUnit::FromMicroseconds(sample->mTimecode) + sample->mDuration, + sample->mTimecode, + sample->mTimecode + sample->mDuration, aFuzz}; if (sampleInterval.ContainsWithStrictEnd(trackData.mNextSampleTimecode)) { @@ -2511,8 +2504,7 @@ TrackBuffersManager::GetNextRandomAccessPoint(TrackInfo::TrackType aTrack, if (sample->mKeyframe) { return TimeUnit::FromMicroseconds(sample->mTime); } - nextSampleTimecode = - TimeUnit::FromMicroseconds(sample->mTimecode) + sample->mDuration; + nextSampleTimecode = sample->mTimecode + sample->mDuration; nextSampleTime = sample->GetEndTime(); } return TimeUnit::FromInfinity(); diff --git a/dom/media/ogg/OggCodecState.cpp b/dom/media/ogg/OggCodecState.cpp index 02ec3404d7ec..6d54bd4ae942 100644 --- a/dom/media/ogg/OggCodecState.cpp +++ b/dom/media/ogg/OggCodecState.cpp @@ -259,7 +259,7 @@ OggCodecState::PacketOutAsMediaRawData() int64_t duration = PacketDuration(packet.get()); NS_ASSERTION(duration >= 0, "duration invalid"); - sample->mTimecode = packet->granulepos; + sample->mTimecode = media::TimeUnit::FromMicroseconds(packet->granulepos); sample->mTime = end_tstamp - duration; sample->mDuration = media::TimeUnit::FromMicroseconds(duration); sample->mKeyframe = IsKeyframe(packet.get()); diff --git a/dom/media/platforms/agnostic/NullDecoderModule.cpp b/dom/media/platforms/agnostic/NullDecoderModule.cpp index be60bdd30441..a9a5909b6b79 100644 --- a/dom/media/platforms/agnostic/NullDecoderModule.cpp +++ b/dom/media/platforms/agnostic/NullDecoderModule.cpp @@ -20,7 +20,7 @@ public: aSample->mTime, aSample->mDuration.ToMicroseconds(), aSample->mKeyframe, - aSample->mTimecode, + aSample->mTimecode.ToMicroseconds(), gfx::IntSize(), 0)); return v.forget(); diff --git a/dom/media/platforms/agnostic/TheoraDecoder.cpp b/dom/media/platforms/agnostic/TheoraDecoder.cpp index 19eb99a4f38c..c8d4f3b91b0f 100644 --- a/dom/media/platforms/agnostic/TheoraDecoder.cpp +++ b/dom/media/platforms/agnostic/TheoraDecoder.cpp @@ -133,7 +133,8 @@ TheoraDecoder::ProcessDecode(MediaRawData* aSample) bool bos = mPacketCount == 0; ogg_packet pkt = InitTheoraPacket( - aData, aLength, bos, false, aSample->mTimecode, mPacketCount++); + aData, aLength, bos, false, + aSample->mTimecode.ToMicroseconds(), mPacketCount++); int ret = th_decode_packetin(mTheoraDecoderContext, &pkt, nullptr); if (ret == 0 || ret == TH_DUPFRAME) { @@ -175,7 +176,7 @@ TheoraDecoder::ProcessDecode(MediaRawData* aSample) aSample->mDuration, b, aSample->mKeyframe, - aSample->mTimecode, + aSample->mTimecode.ToMicroseconds(), mInfo.ScaledImageRect(mTheoraInfo.frame_width, mTheoraInfo.frame_height)); if (!v) { diff --git a/dom/media/platforms/agnostic/VPXDecoder.cpp b/dom/media/platforms/agnostic/VPXDecoder.cpp index 24cc3ea1b7bb..724d5abd40c8 100644 --- a/dom/media/platforms/agnostic/VPXDecoder.cpp +++ b/dom/media/platforms/agnostic/VPXDecoder.cpp @@ -211,7 +211,7 @@ VPXDecoder::ProcessDecode(MediaRawData* aSample) aSample->mDuration, b, aSample->mKeyframe, - aSample->mTimecode, + aSample->mTimecode.ToMicroseconds(), mInfo.ScaledImageRect(img->d_w, img->d_h)); } else { @@ -229,7 +229,7 @@ VPXDecoder::ProcessDecode(MediaRawData* aSample) b, alpha_plane, aSample->mKeyframe, - aSample->mTimecode, + aSample->mTimecode.ToMicroseconds(), mInfo.ScaledImageRect(img->d_w, img->d_h)); diff --git a/dom/media/platforms/agnostic/VorbisDecoder.cpp b/dom/media/platforms/agnostic/VorbisDecoder.cpp index 02886ebd01fd..517261217d79 100644 --- a/dom/media/platforms/agnostic/VorbisDecoder.cpp +++ b/dom/media/platforms/agnostic/VorbisDecoder.cpp @@ -152,8 +152,9 @@ VorbisDataDecoder::ProcessDecode(MediaRawData* aSample) mLastFrameTime = Some(aSample->mTime); } - ogg_packet pkt = InitVorbisPacket(aData, aLength, false, aSample->mEOS, - aSample->mTimecode, mPacketCount++); + ogg_packet pkt = InitVorbisPacket( + aData, aLength, false, aSample->mEOS, + aSample->mTimecode.ToMicroseconds(), mPacketCount++); int err = vorbis_synthesis(&mVorbisBlock, &pkt); if (err) { diff --git a/dom/media/platforms/apple/AppleVTDecoder.cpp b/dom/media/platforms/apple/AppleVTDecoder.cpp index 285670b634bc..7ca6f20c8958 100644 --- a/dom/media/platforms/apple/AppleVTDecoder.cpp +++ b/dom/media/platforms/apple/AppleVTDecoder.cpp @@ -134,7 +134,7 @@ TimingInfoFromSample(MediaRawData* aSample) timestamp.presentationTimeStamp = CMTimeMake(aSample->mTime, USECS_PER_S); timestamp.decodeTimeStamp = - CMTimeMake(aSample->mTimecode, USECS_PER_S); + CMTimeMake(aSample->mTimecode.ToMicroseconds(), USECS_PER_S); return timestamp; } diff --git a/dom/media/platforms/apple/AppleVTDecoder.h b/dom/media/platforms/apple/AppleVTDecoder.h index d902e1de3b19..168077404e38 100644 --- a/dom/media/platforms/apple/AppleVTDecoder.h +++ b/dom/media/platforms/apple/AppleVTDecoder.h @@ -32,7 +32,7 @@ public: bool is_sync_point; explicit AppleFrameRef(const MediaRawData& aSample) - : decode_timestamp(media::TimeUnit::FromMicroseconds(aSample.mTimecode)) + : decode_timestamp(aSample.mTimecode) , composition_timestamp(media::TimeUnit::FromMicroseconds(aSample.mTime)) , duration(aSample.mDuration) , byte_offset(aSample.mOffset) diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp index 2ded77893d9e..518fa024e61c 100644 --- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp @@ -197,7 +197,7 @@ FFmpegVideoDecoder::DoDecode(MediaRawData* aSample, bool* aGotFrame, int size; int len = mLib->av_parser_parse2( mCodecParser, mCodecContext, &data, &size, inputData, inputSize, - aSample->mTime, aSample->mTimecode, aSample->mOffset); + aSample->mTime, aSample->mTimecode.ToMicroseconds(), aSample->mOffset); if (size_t(len) > inputSize) { return NS_ERROR_DOM_MEDIA_DECODE_ERR; } @@ -231,7 +231,7 @@ FFmpegVideoDecoder::DoDecode(MediaRawData* aSample, packet.data = aData; packet.size = aSize; - packet.dts = mLastInputDts = aSample->mTimecode; + packet.dts = mLastInputDts = aSample->mTimecode.ToMicroseconds(); packet.pts = aSample->mTime; packet.flags = aSample->mKeyframe ? AV_PKT_FLAG_KEY : 0; packet.pos = aSample->mOffset; @@ -241,7 +241,8 @@ FFmpegVideoDecoder::DoDecode(MediaRawData* aSample, // As such we instead use a map using the dts as key that we will retrieve // later. // The map will have a typical size of 16 entry. - mDurationMap.Insert(aSample->mTimecode, aSample->mDuration.ToMicroseconds()); + mDurationMap.Insert( + aSample->mTimecode.ToMicroseconds(), aSample->mDuration.ToMicroseconds()); if (!PrepareFrame()) { NS_WARNING("FFmpeg h264 decoder failed to allocate frame."); @@ -362,7 +363,7 @@ RefPtr FFmpegVideoDecoder::ProcessDrain() { RefPtr empty(new MediaRawData()); - empty->mTimecode = mLastInputDts; + empty->mTimecode = media::TimeUnit::FromMicroseconds(mLastInputDts); bool gotFrame = false; DecodedData results; while (NS_SUCCEEDED(DoDecode(empty, &gotFrame, results)) && gotFrame) { diff --git a/dom/media/wave/WaveDemuxer.cpp b/dom/media/wave/WaveDemuxer.cpp index dd1a7ca3e99c..7c0923e2b31f 100644 --- a/dom/media/wave/WaveDemuxer.cpp +++ b/dom/media/wave/WaveDemuxer.cpp @@ -540,7 +540,7 @@ WAVTrackDemuxer::GetNextChunk(const MediaByteRange& aRange) mDataLength - mChunkIndex * DATA_CHUNK_SIZE; datachunk->mDuration = DurationFromBytes(mBytesRemaining); } - datachunk->mTimecode = datachunk->mTime; + datachunk->mTimecode = media::TimeUnit::FromMicroseconds(datachunk->mTime); datachunk->mKeyframe = true; MOZ_ASSERT(datachunk->mTime >= 0); diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index 51d0f37eceea..9e0bf56e8cec 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -722,7 +722,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, return NS_ERROR_OUT_OF_MEMORY; } } - sample->mTimecode = tstamp; + sample->mTimecode = media::TimeUnit::FromMicroseconds(tstamp); sample->mTime = tstamp; sample->mDuration = media::TimeUnit::FromMicroseconds(next_tstamp - tstamp); sample->mOffset = holder->Offset(); @@ -1157,7 +1157,7 @@ WebMTrackDemuxer::SetNextKeyFrameTime() Maybe startTime; if (skipSamplesQueue.GetSize()) { const RefPtr& sample = skipSamplesQueue.First(); - startTime.emplace(sample->mTimecode); + startTime.emplace(sample->mTimecode.ToMicroseconds()); } // Demux and buffer frames until we find a keyframe. RefPtr sample; @@ -1167,7 +1167,7 @@ WebMTrackDemuxer::SetNextKeyFrameTime() frameTime = sample->mTime; foundKeyframe = true; } - int64_t sampleTimecode = sample->mTimecode; + int64_t sampleTimecode = sample->mTimecode.ToMicroseconds(); skipSamplesQueue.Push(sample.forget()); if (!startTime) { startTime.emplace(sampleTimecode); @@ -1186,9 +1186,7 @@ WebMTrackDemuxer::SetNextKeyFrameTime() WEBM_DEBUG("Next Keyframe %f (%u queued %.02fs)", mNextKeyframeTime.value().ToSeconds(), uint32_t(mSamples.GetSize()), - media::TimeUnit::FromMicroseconds(mSamples.Last()->mTimecode - - mSamples.First()->mTimecode) - .ToSeconds()); + (mSamples.Last()->mTimecode - mSamples.First()->mTimecode).ToSeconds()); } else { WEBM_DEBUG("Couldn't determine next keyframe time (%u queued)", uint32_t(mSamples.GetSize())); diff --git a/media/libstagefright/binding/Index.cpp b/media/libstagefright/binding/Index.cpp index 0399a142bb6c..73d5be405a2a 100644 --- a/media/libstagefright/binding/Index.cpp +++ b/media/libstagefright/binding/Index.cpp @@ -100,7 +100,7 @@ already_AddRefed SampleIterator::GetNext() } RefPtr sample = new MediaRawData(); - sample->mTimecode= s->mDecodeTime; + sample->mTimecode= TimeUnit::FromMicroseconds(s->mDecodeTime); sample->mTime = s->mCompositionRange.start; sample->mDuration = TimeUnit::FromMicroseconds(s->mCompositionRange.Length()); sample->mOffset = s->mByteRange.mStart; From 29488c9b00efbfce852c556d0b967d6fff9b8a89 Mon Sep 17 00:00:00 2001 From: Matthew Wein Date: Wed, 15 Mar 2017 21:02:56 -0400 Subject: [PATCH 02/65] Bug 1331742 - Part 1 - Create and register browser_action.json r=mixedpuppy MozReview-Commit-ID: AwYuTDU3Ki4 --HG-- rename : browser/components/extensions/schemas/browser_action.json => mobile/android/components/extensions/schemas/browser_action.json extra : rebase_source : 40d21958c2800a35e9a691f379694c6ca3b1c73e --- .../extensions/extensions-mobile.manifest | 2 +- .../extensions/schemas/browser_action.json | 451 ++++++++++++++++++ .../components/extensions/schemas/jar.mn | 1 + 3 files changed, 453 insertions(+), 1 deletion(-) create mode 100644 mobile/android/components/extensions/schemas/browser_action.json diff --git a/mobile/android/components/extensions/extensions-mobile.manifest b/mobile/android/components/extensions/extensions-mobile.manifest index 77fec486600a..7c514f77abca 100644 --- a/mobile/android/components/extensions/extensions-mobile.manifest +++ b/mobile/android/components/extensions/extensions-mobile.manifest @@ -1,4 +1,4 @@ -# scripts +# modules category webextension-scripts android chrome://browser/content/ext-android.js category webextension-scripts utils chrome://browser/content/ext-utils.js category webextension-scripts-addon android chrome://browser/content/ext-c-android.js diff --git a/mobile/android/components/extensions/schemas/browser_action.json b/mobile/android/components/extensions/schemas/browser_action.json new file mode 100644 index 000000000000..2333679e6c90 --- /dev/null +++ b/mobile/android/components/extensions/schemas/browser_action.json @@ -0,0 +1,451 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +[ + { + "namespace": "manifest", + "types": [ + { + "$extend": "WebExtensionManifest", + "properties": { + "browser_action": { + "type": "object", + "additionalProperties": { "$ref": "UnrecognizedProperty" }, + "properties": { + "default_title": { + "type": "string", + "optional": true, + "preprocess": "localize" + }, + "default_icon": { + "$ref": "IconPath", + "unsupported": true, + "optional": true + }, + "default_popup": { + "type": "string", + "format": "relativeUrl", + "unsupported": true, + "optional": true, + "preprocess": "localize" + }, + "browser_style": { + "type": "boolean", + "unsupported": true, + "optional": true + }, + "default_area": { + "description": "Defines the location the browserAction will appear by default. The default location is navbar.", + "type": "string", + "enum": ["navbar", "menupanel", "tabstrip", "personaltoolbar"], + "unsupported": true, + "optional": true + } + }, + "optional": true + } + } + } + ] + }, + { + "namespace": "browserAction", + "description": "Use browser actions to put icons in the main browser toolbar, to the right of the address bar. In addition to its icon, a browser action can also have a tooltip, a badge, and a popup.", + "permissions": ["manifest:browser_action"], + "types": [ + { + "id": "ColorArray", + "type": "array", + "items": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "minItems": 4, + "maxItems": 4 + }, + { + "id": "ImageDataType", + "type": "object", + "isInstanceOf": "ImageData", + "additionalProperties": { "type": "any" }, + "postprocess": "convertImageDataToURL", + "description": "Pixel data for an image. Must be an ImageData object (for example, from a canvas element)." + } + ], + "functions": [ + { + "name": "setTitle", + "unsupported": true, + "type": "function", + "description": "Sets the title of the browser action. This shows up in the tooltip.", + "async": "callback", + "parameters": [ + { + "name": "details", + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "The string the browser action should display when moused over." + }, + "tabId": { + "type": "integer", + "optional": true, + "description": "Limits the change to when a particular tab is selected. Automatically resets when the tab is closed." + } + } + }, + { + "type": "function", + "name": "callback", + "optional": true, + "parameters": [] + } + ] + }, + { + "name": "getTitle", + "unsupported": true, + "type": "function", + "description": "Gets the title of the browser action.", + "async": "callback", + "parameters": [ + { + "name": "details", + "type": "object", + "properties": { + "tabId": { + "type": "integer", + "optional": true, + "description": "Specify the tab to get the title from. If no tab is specified, the non-tab-specific title is returned." + } + } + }, + { + "type": "function", + "name": "callback", + "parameters": [ + { + "name": "result", + "type": "string" + } + ] + } + ] + }, + { + "name": "setIcon", + "unsupported": true, + "type": "function", + "description": "Sets the icon for the browser action. The icon can be specified either as the path to an image file or as the pixel data from a canvas element, or as dictionary of either one of those. Either the path or the imageData property must be specified.", + "async": "callback", + "parameters": [ + { + "name": "details", + "type": "object", + "properties": { + "imageData": { + "choices": [ + { "$ref": "ImageDataType" }, + { + "type": "object", + "additionalProperties": {"$ref": "ImageDataType"} + } + ], + "optional": true, + "description": "Either an ImageData object or a dictionary {size -> ImageData} representing icon to be set. If the icon is specified as a dictionary, the actual image to be used is chosen depending on screen's pixel density. If the number of image pixels that fit into one screen space unit equals scale, then image with size scale * 19 will be selected. Initially only scales 1 and 2 will be supported. At least one image must be specified. Note that 'details.imageData = foo' is equivalent to 'details.imageData = {'19': foo}'" + }, + "path": { + "choices": [ + { "type": "string" }, + { + "type": "object", + "additionalProperties": {"type": "string"} + } + ], + "optional": true, + "description": "Either a relative image path or a dictionary {size -> relative image path} pointing to icon to be set. If the icon is specified as a dictionary, the actual image to be used is chosen depending on screen's pixel density. If the number of image pixels that fit into one screen space unit equals scale, then image with size scale * 19 will be selected. Initially only scales 1 and 2 will be supported. At least one image must be specified. Note that 'details.path = foo' is equivalent to 'details.imageData = {'19': foo}'" + }, + "tabId": { + "type": "integer", + "optional": true, + "description": "Limits the change to when a particular tab is selected. Automatically resets when the tab is closed." + } + } + }, + { + "type": "function", + "name": "callback", + "optional": true, + "parameters": [] + } + ] + }, + { + "name": "setPopup", + "unsupported": true, + "type": "function", + "description": "Sets the html document to be opened as a popup when the user clicks on the browser action's icon.", + "async": "callback", + "parameters": [ + { + "name": "details", + "type": "object", + "properties": { + "tabId": { + "type": "integer", + "optional": true, + "minimum": 0, + "description": "Limits the change to when a particular tab is selected. Automatically resets when the tab is closed." + }, + "popup": { + "type": "string", + "description": "The html file to show in a popup. If set to the empty string (''), no popup is shown." + } + } + }, + { + "type": "function", + "name": "callback", + "optional": true, + "parameters": [] + } + ] + }, + { + "name": "getPopup", + "unsupported": true, + "type": "function", + "description": "Gets the html document set as the popup for this browser action.", + "async": "callback", + "parameters": [ + { + "name": "details", + "type": "object", + "properties": { + "tabId": { + "type": "integer", + "optional": true, + "description": "Specify the tab to get the popup from. If no tab is specified, the non-tab-specific popup is returned." + } + } + }, + { + "type": "function", + "name": "callback", + "parameters": [ + { + "name": "result", + "type": "string" + } + ] + } + ] + }, + { + "name": "setBadgeText", + "unsupported": true, + "type": "function", + "description": "Sets the badge text for the browser action. The badge is displayed on top of the icon.", + "async": "callback", + "parameters": [ + { + "name": "details", + "type": "object", + "properties": { + "text": { + "type": "string", + "description": "Any number of characters can be passed, but only about four can fit in the space." + }, + "tabId": { + "type": "integer", + "optional": true, + "description": "Limits the change to when a particular tab is selected. Automatically resets when the tab is closed." + } + } + }, + { + "type": "function", + "name": "callback", + "optional": true, + "parameters": [] + } + ] + }, + { + "name": "getBadgeText", + "unsupported": true, + "type": "function", + "description": "Gets the badge text of the browser action. If no tab is specified, the non-tab-specific badge text is returned.", + "async": "callback", + "parameters": [ + { + "name": "details", + "type": "object", + "properties": { + "tabId": { + "type": "integer", + "optional": true, + "description": "Specify the tab to get the badge text from. If no tab is specified, the non-tab-specific badge text is returned." + } + } + }, + { + "type": "function", + "name": "callback", + "parameters": [ + { + "name": "result", + "type": "string" + } + ] + } + ] + }, + { + "name": "setBadgeBackgroundColor", + "unsupported": true, + "type": "function", + "description": "Sets the background color for the badge.", + "async": "callback", + "parameters": [ + { + "name": "details", + "type": "object", + "properties": { + "color": { + "description": "An array of four integers in the range [0,255] that make up the RGBA color of the badge. For example, opaque red is [255, 0, 0, 255]. Can also be a string with a CSS value, with opaque red being #FF0000 or #F00.", + "choices": [ + {"type": "string"}, + {"$ref": "ColorArray"} + ] + }, + "tabId": { + "type": "integer", + "optional": true, + "description": "Limits the change to when a particular tab is selected. Automatically resets when the tab is closed." + } + } + }, + { + "type": "function", + "name": "callback", + "optional": true, + "parameters": [] + } + ] + }, + { + "name": "getBadgeBackgroundColor", + "unsupported": true, + "type": "function", + "description": "Gets the background color of the browser action.", + "async": "callback", + "parameters": [ + { + "name": "details", + "type": "object", + "properties": { + "tabId": { + "type": "integer", + "optional": true, + "description": "Specify the tab to get the badge background color from. If no tab is specified, the non-tab-specific badge background color is returned." + } + } + }, + { + "type": "function", + "name": "callback", + "parameters": [ + { + "name": "result", + "$ref": "ColorArray" + } + ] + } + ] + }, + { + "name": "enable", + "unsupported": true, + "type": "function", + "description": "Enables the browser action for a tab. By default, browser actions are enabled.", + "async": "callback", + "parameters": [ + { + "type": "integer", + "optional": true, + "name": "tabId", + "minimum": 0, + "description": "The id of the tab for which you want to modify the browser action." + }, + { + "type": "function", + "name": "callback", + "optional": true, + "parameters": [] + } + ] + }, + { + "name": "disable", + "unsupported": true, + "type": "function", + "description": "Disables the browser action for a tab.", + "async": "callback", + "parameters": [ + { + "type": "integer", + "optional": true, + "name": "tabId", + "minimum": 0, + "description": "The id of the tab for which you want to modify the browser action." + }, + { + "type": "function", + "name": "callback", + "optional": true, + "parameters": [] + } + ] + }, + { + "name": "openPopup", + "unsupported": true, + "type": "function", + "description": "Opens the extension popup window in the active window but does not grant tab permissions.", + "async": "callback", + "parameters": [ + { + "type": "function", + "name": "callback", + "parameters": [ + { + "name": "popupView", + "type": "object", + "optional": true, + "description": "JavaScript 'window' object for the popup window if it was succesfully opened.", + "additionalProperties": { "type": "any" } + } + ] + } + ] + } + ], + "events": [ + { + "name": "onClicked", + "type": "function", + "description": "Fired when a browser action icon is clicked. This event will not fire if the browser action has a popup.", + "parameters": [ + { + "name": "tab", + "$ref": "tabs.Tab" + } + ] + } + ] + } +] diff --git a/mobile/android/components/extensions/schemas/jar.mn b/mobile/android/components/extensions/schemas/jar.mn index 53d83eb90e19..af7577f55e61 100644 --- a/mobile/android/components/extensions/schemas/jar.mn +++ b/mobile/android/components/extensions/schemas/jar.mn @@ -3,5 +3,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. chrome.jar: + content/schemas/browser_action.json content/schemas/page_action.json content/schemas/tabs.json From 35c2d73d834d70a1456b6b2beaf44ac44e96757b Mon Sep 17 00:00:00 2001 From: Matthew Wein Date: Sat, 25 Mar 2017 22:36:05 -0700 Subject: [PATCH 03/65] Bug 1331742 - Part 2 - Create a module for managing browser actions similar to PageActions.jsm r=sebastian MozReview-Commit-ID: 2epdMD75e84 --HG-- extra : rebase_source : a542b3ca2e673e4fcfdebab56108c2df66239630 --- mobile/android/modules/BrowserActions.jsm | 113 ++++++++++++++++++++++ mobile/android/modules/PageActions.jsm | 18 ++-- mobile/android/modules/moz.build | 1 + 3 files changed, 123 insertions(+), 9 deletions(-) create mode 100644 mobile/android/modules/BrowserActions.jsm diff --git a/mobile/android/modules/BrowserActions.jsm b/mobile/android/modules/BrowserActions.jsm new file mode 100644 index 000000000000..08c3a7acb4e2 --- /dev/null +++ b/mobile/android/modules/BrowserActions.jsm @@ -0,0 +1,113 @@ +/* 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/. */ + +"use strict"; + +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/Messaging.jsm"); + +this.EXPORTED_SYMBOLS = ["BrowserActions"]; + +var BrowserActions = { + _browserActions: {}, + + _initialized: false, + + /** + * Registers the listeners only if they have not been initialized + * already and there is at least one browser action. + */ + _maybeRegisterListeners() { + if (!this._initialized && Object.keys(this._browserActions).length) { + this._initialized = true; + EventDispatcher.instance.registerListener(this, "Menu:Clicked"); + } + }, + + /** + * Unregisters the listeners if they are already initizliaed and + * all of the browser actions have been removed. + */ + _maybeUnregisterListeners: function() { + if (this._initialized && !Object.keys(this._browserActions).length) { + this._initialized = false; + EventDispatcher.instance.unregisterListener(this, "Menu:Clicked"); + } + }, + + /** + * Called when a browser action is clicked on. + * @param {string} event The name of the event, which should always + * be "Menu:Clicked". + * @param {Object} data An object containing information about the + * browser action, which in this case should contain an `item` + * property which is browser action's ID. + */ + onEvent(event, data) { + if (event !== "Menu:Clicked") { + throw new Error(`Expected "Menu:Clicked" event - received "${event}" instead`); + } + + let browserAction = this._browserActions[data.item]; + if (!browserAction) { + throw new Error(`No browser action found with id ${data.item}`); + } + browserAction.onClicked(); + }, + + /** + * Registers a new browser action. + * @param {Object} browserAction The browser action to add. + */ + register(browserAction) { + EventDispatcher.instance.sendRequest({ + type: "Menu:Add", + id: browserAction.id, + name: browserAction.name, + }); + + this._browserActions[browserAction.id] = browserAction; + this._maybeRegisterListeners(); + }, + + /** + * Checks to see if the browser action is shown. Used for testing only. + * @param {string} id The ID of the browser action. + * @returns True if the browser action is shown; false otherwise. + */ + isShown: function(id) { + return !!this._browserActions[id]; + }, + + /** + * Synthesizes a click on the browser action. Used for testing only. + * @param {string} id The ID of the browser action. + */ + synthesizeClick: function(id) { + let browserAction = this._browserActions[id]; + if (!browserAction) { + throw new Error(`No browser action found with id ${id}`); + } + browserAction.onClicked(); + }, + + /** + * Unregisters the browser action with the specified ID. + * @param {string} id The browser action ID. + */ + unregister(id) { + let browserAction = this._browserActions[id]; + if (!browserAction) { + throw new Error(`No BrowserAction with ID ${id} was found`); + } + EventDispatcher.instance.sendRequest({ + type: "Menu:Remove", + id, + }); + delete this._browserActions[id]; + this._maybeUnregisterListeners(); + } +} \ No newline at end of file diff --git a/mobile/android/modules/PageActions.jsm b/mobile/android/modules/PageActions.jsm index 745e4a1146ae..30295b6a7f54 100644 --- a/mobile/android/modules/PageActions.jsm +++ b/mobile/android/modules/PageActions.jsm @@ -34,11 +34,11 @@ function resolveGeckoURI(aURI) { var PageActions = { _items: { }, - _inited: false, + _initialized: false, - _maybeInit: function() { - if (!this._inited && Object.keys(this._items).length > 0) { - this._inited = true; + _maybeInitialize: function() { + if (!this._initialized && Object.keys(this._items).length) { + this._initialized = true; EventDispatcher.instance.registerListener(this, [ "PageActions:Clicked", "PageActions:LongClicked", @@ -46,9 +46,9 @@ var PageActions = { } }, - _maybeUninit: function() { - if (this._inited && Object.keys(this._items).length == 0) { - this._inited = false; + _maybeUninitialize: function() { + if (this._initialized && !Object.keys(this._items).length) { + this._initialized = false; EventDispatcher.instance.unregisterListener(this, [ "PageActions:Clicked", "PageActions:LongClicked", @@ -101,7 +101,7 @@ var PageActions = { this._items[id].longClickCallback = aOptions.longClickCallback; } - this._maybeInit(); + this._maybeInitialize(); return id; }, @@ -112,6 +112,6 @@ var PageActions = { }); delete this._items[id]; - this._maybeUninit(); + this._maybeUninitialize(); } } diff --git a/mobile/android/modules/moz.build b/mobile/android/modules/moz.build index 88e8412fd69d..bd9d05b34578 100644 --- a/mobile/android/modules/moz.build +++ b/mobile/android/modules/moz.build @@ -21,6 +21,7 @@ DIRS += ['geckoview'] EXTRA_JS_MODULES += [ 'Accounts.jsm', + 'BrowserActions.jsm', 'dbg-browser-actors.js', 'DelayedInit.jsm', 'DownloadNotifications.jsm', From 0bb36b786bf7a4deab4ed8cf909e43ad43caccdf Mon Sep 17 00:00:00 2001 From: Matthew Wein Date: Wed, 19 Apr 2017 21:44:41 -0400 Subject: [PATCH 04/65] Bug 1331742 - Part 3 - Create and register ext-browserAction.js r=mixedpuppy MozReview-Commit-ID: CGR4689b6oo --HG-- extra : rebase_source : 912519c647c2051d03307f52ca778efb1f9e7480 --- .../components/extensions/ext-android.js | 9 +++ .../extensions/ext-browserAction.js | 78 +++++++++++++++++++ mobile/android/components/extensions/jar.mn | 1 + 3 files changed, 88 insertions(+) create mode 100644 mobile/android/components/extensions/ext-browserAction.js diff --git a/mobile/android/components/extensions/ext-android.js b/mobile/android/components/extensions/ext-android.js index 69f96908a9ae..b781438b5bd0 100644 --- a/mobile/android/components/extensions/ext-android.js +++ b/mobile/android/components/extensions/ext-android.js @@ -47,6 +47,15 @@ extensions.on("page-shutdown", (type, context) => { extensions.registerModules({ + browserAction: { + url: "chrome://browser/content/ext-browserAction.js", + schema: "chrome://browser/content/schemas/browser_action.json", + scopes: ["addon_parent"], + manifest: ["browser_action"], + paths: [ + ["browserAction"], + ], + }, pageAction: { url: "chrome://browser/content/ext-pageAction.js", schema: "chrome://browser/content/schemas/page_action.json", diff --git a/mobile/android/components/extensions/ext-browserAction.js b/mobile/android/components/extensions/ext-browserAction.js new file mode 100644 index 000000000000..710203518b92 --- /dev/null +++ b/mobile/android/components/extensions/ext-browserAction.js @@ -0,0 +1,78 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter", + "resource://devtools/shared/event-emitter.js"); + +XPCOMUtils.defineLazyModuleGetter(this, "Services", + "resource://gre/modules/Services.jsm"); + +// Import the android BrowserActions module. +XPCOMUtils.defineLazyModuleGetter(this, "BrowserActions", + "resource://gre/modules/BrowserActions.jsm"); + +// WeakMap[Extension -> BrowserAction] +var browserActionMap = new WeakMap(); + +class BrowserAction { + constructor(options, extension) { + this.id = `{${extension.uuid}}`; + this.name = options.default_title || extension.name; + BrowserActions.register(this); + EventEmitter.decorate(this); + } + + /** + * Required by the BrowserActions module. This event will get + * called whenever the browser action is clicked on. + */ + onClicked() { + this.emit("click", tabTracker.activeTab); + } + + /** + * Unregister the browser action from the BrowserActions module. + */ + shutdown() { + BrowserActions.unregister(this.id); + } +} + +this.browserAction = class extends ExtensionAPI { + onManifestEntry(entryName) { + let {extension} = this; + let {manifest} = extension; + + let browserAction = new BrowserAction(manifest.browser_action, extension); + browserActionMap.set(extension, browserAction); + } + + onShutdown(reason) { + let {extension} = this; + + if (browserActionMap.has(extension)) { + browserActionMap.get(extension).shutdown(); + browserActionMap.delete(extension); + } + } + + getAPI(context) { + const {extension} = context; + const {tabManager} = extension; + + return { + browserAction: { + onClicked: new SingletonEventManager(context, "browserAction.onClicked", fire => { + let listener = (event, tab) => { + fire.async(tabManager.convert(tab)); + }; + browserActionMap.get(extension).on("click", listener); + return () => { + browserActionMap.get(extension).off("click", listener); + }; + }).api(), + }, + }; + } +}; diff --git a/mobile/android/components/extensions/jar.mn b/mobile/android/components/extensions/jar.mn index 30412827632f..222cfc802e6c 100644 --- a/mobile/android/components/extensions/jar.mn +++ b/mobile/android/components/extensions/jar.mn @@ -6,6 +6,7 @@ chrome.jar: content/ext-android.js content/ext-c-android.js content/ext-c-tabs.js + content/ext-browserAction.js content/ext-pageAction.js content/ext-tabs.js content/ext-utils.js From 549d74a6055c77d38905b113467cab76840ba6e7 Mon Sep 17 00:00:00 2001 From: Matthew Wein Date: Sat, 25 Mar 2017 22:35:54 -0700 Subject: [PATCH 05/65] Bug 1331742 - Part 4 - Add a position property to keep track of the menu item's position instead of using the ID r=sebastian MozReview-Commit-ID: 7ZtfaVQFhKX --HG-- extra : rebase_source : b1d9a62ca8c272eb4ff631d4331129c97153cb31 --- .../java/org/mozilla/gecko/BrowserApp.java | 57 ++++++++++++------- mobile/android/chrome/content/browser.js | 18 +++--- 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java index 37fe1a4c85a1..cbff747992ac 100644 --- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java +++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java @@ -230,7 +230,7 @@ public class BrowserApp extends GeckoApp public ActionModeCompatView mActionBar; private VideoPlayer mVideoPlayer; private BrowserToolbar mBrowserToolbar; - private View doorhangerOverlay; + private View mDoorhangerOverlay; // We can't name the TabStrip class because it's not included on API 9. private TabStripInterface mTabStrip; private ToolbarProgressView mProgressView; @@ -253,8 +253,9 @@ public class BrowserApp extends GeckoApp public static final String TAB_HISTORY_FRAGMENT_TAG = "tabHistoryFragment"; private static class MenuItemInfo { - public int id; + public String id; public String label; + public int position; public boolean checkable; public boolean checked; public boolean enabled = true; @@ -289,6 +290,9 @@ public class BrowserApp extends GeckoApp // Stored value of the toolbar height, so we know when it's changed. private int mToolbarHeight; + // The ID to use for the next addon menu item. + private int mNextAddonMenuId = 0; + private SharedPreferencesHelper mSharedPreferencesHelper; private ReadingListHelper mReadingListHelper; @@ -730,7 +734,7 @@ public class BrowserApp extends GeckoApp mFindInPageBar = (FindInPageBar) findViewById(R.id.find_in_page); mMediaCastingBar = (MediaCastingBar) findViewById(R.id.media_casting); - doorhangerOverlay = findViewById(R.id.doorhanger_overlay); + mDoorhangerOverlay = findViewById(R.id.doorhanger_overlay); EventDispatcher.getInstance().registerGeckoThreadListener(this, "Search:Keyword", @@ -1844,8 +1848,7 @@ public class BrowserApp extends GeckoApp break; case "Menu:Update": - updateAddonMenuItem(message.getInt("id") + ADDON_MENU_OFFSET, - message.getBundle("options")); + updateAddonMenuItem(message.getString("id"), message.getBundle("options")); break; case "Menu:Add": @@ -1855,7 +1858,8 @@ public class BrowserApp extends GeckoApp Log.e(LOGTAG, "Invalid menu item name"); return; } - info.id = message.getInt("id") + ADDON_MENU_OFFSET; + info.id = message.getString("id"); + info.position = ADDON_MENU_OFFSET + mNextAddonMenuId; info.checked = message.getBoolean("checked", false); info.enabled = message.getBoolean("enabled", true); info.visible = message.getBoolean("visible", true); @@ -1863,10 +1867,11 @@ public class BrowserApp extends GeckoApp final int parent = message.getInt("parent", 0); info.parent = parent <= 0 ? parent : parent + ADDON_MENU_OFFSET; addAddonMenuItem(info); + mNextAddonMenuId++; break; case "Menu:Remove": - removeAddonMenuItem(message.getInt("id") + ADDON_MENU_OFFSET); + removeAddonMenuItem(message.getString("id")); break; case "LightweightTheme:Update": @@ -3137,13 +3142,13 @@ public class BrowserApp extends GeckoApp } } - final MenuItem item = destination.add(Menu.NONE, info.id, Menu.NONE, info.label); + final MenuItem item = destination.add(Menu.NONE, info.position, Menu.NONE, info.label); item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { final GeckoBundle data = new GeckoBundle(1); - data.putInt("item", info.id - ADDON_MENU_OFFSET); + data.putString("item", info.id); EventDispatcher.getInstance().dispatch("Menu:Clicked", data); return true; } @@ -3173,30 +3178,38 @@ public class BrowserApp extends GeckoApp addAddonMenuItemToMenu(mMenu, info); } - private void removeAddonMenuItem(int id) { + private void removeAddonMenuItem(String id) { + int position = -1; + // Remove add-on menu item from cache, if available. if (mAddonMenuItemsCache != null && !mAddonMenuItemsCache.isEmpty()) { for (MenuItemInfo item : mAddonMenuItemsCache) { - if (item.id == id) { - mAddonMenuItemsCache.remove(item); - break; - } + if (item.id.equals(id)) { + position = item.position; + mAddonMenuItemsCache.remove(item); + break; + } } } - if (mMenu == null) + if (mMenu == null || position == -1) return; - final MenuItem menuItem = mMenu.findItem(id); - if (menuItem != null) - mMenu.removeItem(id); + final MenuItem menuItem = mMenu.findItem(position); + if (menuItem != null) { + mNextAddonMenuId--; + mMenu.removeItem(position); + } } - private void updateAddonMenuItem(int id, final GeckoBundle options) { + private void updateAddonMenuItem(String id, final GeckoBundle options) { + int position = -1; + // Set attribute for the menu item in cache, if available if (mAddonMenuItemsCache != null && !mAddonMenuItemsCache.isEmpty()) { for (MenuItemInfo item : mAddonMenuItemsCache) { if (item.id == id) { + position = item.position; item.label = options.getString("name", item.label); item.checkable = options.getBoolean("checkable", item.checkable); item.checked = options.getBoolean("checked", item.checked); @@ -3208,11 +3221,11 @@ public class BrowserApp extends GeckoApp } } - if (mMenu == null) { + if (mMenu == null || position == -1) { return; } - final MenuItem menuItem = mMenu.findItem(id); + final MenuItem menuItem = mMenu.findItem(position); if (menuItem != null) { menuItem.setTitle(options.getString("name", menuItem.getTitle().toString())); menuItem.setCheckable(options.getBoolean("checkable", menuItem.isCheckable())); @@ -4070,7 +4083,7 @@ public class BrowserApp extends GeckoApp @Override public View getDoorhangerOverlay() { - return doorhangerOverlay; + return mDoorhangerOverlay; } public SearchEngineManager getSearchEngineManager() { diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index b137a448d1b8..ab66c8971450 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -2265,7 +2265,6 @@ var NativeWindow = { menu: { _callbacks: [], - _menuId: 1, toolsMenuID: -1, add: function() { let options; @@ -2282,25 +2281,26 @@ var NativeWindow = { } options.type = "Menu:Add"; - options.id = this._menuId; + + let uuid = uuidgen.generateUUID().toString(); + options.id = uuid; GlobalEventDispatcher.sendRequest(options); - this._callbacks[this._menuId] = options.callback; - this._menuId++; - return this._menuId - 1; + this._callbacks[uuid] = options.callback; + return uuid; }, - remove: function(aId) { - GlobalEventDispatcher.sendRequest({ type: "Menu:Remove", id: aId }); + remove: function(uuid) { + GlobalEventDispatcher.sendRequest({ type: "Menu:Remove", id: uuid }); }, - update: function(aId, aOptions) { + update: function(uuid, aOptions) { if (!aOptions) return; GlobalEventDispatcher.sendRequest({ type: "Menu:Update", - id: aId, + id: uuid, options: aOptions }); } From 09d1616dc77fc00ad5cfed214ef8aeadee9324f9 Mon Sep 17 00:00:00 2001 From: Matthew Wein Date: Mon, 10 Apr 2017 16:15:54 -0400 Subject: [PATCH 06/65] Bug 1331742 - Part 5 - Add unit tests for browserAction.onClicked r=mixedpuppy MozReview-Commit-ID: Ko8eQYfIM0H --HG-- extra : rebase_source : 0774a850694d8ea52d7c39872e5ac02f4acec4c5 --- .../extensions/test/mochitest/chrome.ini | 1 + .../extensions/test/mochitest/head.js | 11 +-- .../test_ext_browserAction_onClicked.html | 94 +++++++++++++++++++ .../test/mochitest/test_ext_pageAction.html | 25 +++-- .../mochitest/test_ext_pageAction_popup.html | 22 ++--- .../content/SpecialPowersObserverAPI.js | 2 +- .../specialpowers/content/specialpowersAPI.js | 1 + .../extensions/ExtensionXPCShellUtils.jsm | 1 + 8 files changed, 120 insertions(+), 37 deletions(-) create mode 100644 mobile/android/components/extensions/test/mochitest/test_ext_browserAction_onClicked.html diff --git a/mobile/android/components/extensions/test/mochitest/chrome.ini b/mobile/android/components/extensions/test/mochitest/chrome.ini index 94473b1a59b0..30d26b908ff6 100644 --- a/mobile/android/components/extensions/test/mochitest/chrome.ini +++ b/mobile/android/components/extensions/test/mochitest/chrome.ini @@ -4,5 +4,6 @@ support-files = ../../../../../../toolkit/components/extensions/test/mochitest/chrome_cleanup_script.js tags = webextensions +[test_ext_browserAction_onClicked.html] [test_ext_pageAction.html] [test_ext_pageAction_popup.html] diff --git a/mobile/android/components/extensions/test/mochitest/head.js b/mobile/android/components/extensions/test/mochitest/head.js index f546fd503e63..8b6e26768dd7 100644 --- a/mobile/android/components/extensions/test/mochitest/head.js +++ b/mobile/android/components/extensions/test/mochitest/head.js @@ -1,9 +1,8 @@ "use strict"; -/* exported isPageActionShown clickPageAction, AppConstants */ +/* exported AppConstants */ var {AppConstants} = SpecialPowers.Cu.import("resource://gre/modules/AppConstants.jsm", {}); -var {PageActions} = SpecialPowers.Cu.import("resource://gre/modules/PageActions.jsm", {}); { let chromeScript = SpecialPowers.loadChromeScript( @@ -22,11 +21,3 @@ var {PageActions} = SpecialPowers.Cu.import("resource://gre/modules/PageActions. } }); } - -function isPageActionShown(uuid) { - return PageActions.isShown(uuid); -} - -function clickPageAction(uuid) { - PageActions.synthesizeClick(uuid); -} diff --git a/mobile/android/components/extensions/test/mochitest/test_ext_browserAction_onClicked.html b/mobile/android/components/extensions/test/mochitest/test_ext_browserAction_onClicked.html new file mode 100644 index 000000000000..076877cdf867 --- /dev/null +++ b/mobile/android/components/extensions/test/mochitest/test_ext_browserAction_onClicked.html @@ -0,0 +1,94 @@ + + + + BrowserAction Test + + + + + + + + + + + + diff --git a/mobile/android/components/extensions/test/mochitest/test_ext_pageAction.html b/mobile/android/components/extensions/test/mochitest/test_ext_pageAction.html index 05d8f38efe19..42affbdb250c 100644 --- a/mobile/android/components/extensions/test/mochitest/test_ext_pageAction.html +++ b/mobile/android/components/extensions/test/mochitest/test_ext_pageAction.html @@ -13,6 +13,8 @@ diff --git a/mobile/android/components/extensions/test/mochitest/test_ext_pageAction_popup.html b/mobile/android/components/extensions/test/mochitest/test_ext_pageAction_popup.html index b110a272d545..729e25f05cdd 100644 --- a/mobile/android/components/extensions/test/mochitest/test_ext_pageAction_popup.html +++ b/mobile/android/components/extensions/test/mochitest/test_ext_pageAction_popup.html @@ -17,12 +17,14 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://gre/modules/Services.jsm"); +var {PageActions} = Cu.import("resource://gre/modules/PageActions.jsm", {}); + let dataURI = "iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAC4klEQVRYhdWXLWzbQBSADQtDAwsHC1tUhUxqfL67lk2tdn+OJg0ODU0rLByqgqINBY6tmlbn7LMTJ5FaFVVBk1G0oUGjG2jT2Y7jxmmcbU/6iJ+f36fz+e5sGP9riCGm9hB37RG+scd4Yo/wsDXCZyIE2xuXsce4bY+wXkAsQtzYmExrfFgvkJkRbkzo1ehoxx5iXcgI/9iYUGt8WH9MqDXEcmNChmEYrRCf2SHWeYgQx3x0tLNRIeKQLTtEFyJEep4NTuhk8BC+yMrwEE3+iozo42d8gK7FAOkMsRiiN8QhW2ttSK5QTfRRV4QoymVeJMvPvDp7gCZigD613MN6yRFA3SWarow9QB9LCfG+NeF9qCtjAKOSQjCqVKhfVsiHEQ+grgx/lRGqUihAc1uL8EFD+KCRO+GrF4J61phcoRoPoEzkYhZYpykh5sMb7kOdIeY+jHKur4QI4Feh4AFX1nVeLxrAvQchGsBz5ls6wa2QdwcvIcE2863bTH79KOvsz/uUYJsp+J0pSzNlDckVqqVGUAF+n6uS7txcOl6wot4JVy70ufDLy4pWLUQVPE81pRI0mGe9oxLMHSeohHvMs/STUNaUK6vDPCvOyxMFDx4achehRDJmHnydnkPww5OFfLxrGIZBFDyYl4LpMzlTQFIP6AQx86w2UeYBccFpJrcKv5L9eGDtUAU6RIELqsB74uynjy/UBRF1gS5BTFxwQT1wTiXoUg9MH7m/3NZRRoi5IJytUbMgzv4Wc832+oQkiKgEehmyMkkpKsFkQV11QsRJL5rJYBLItQgRaUZEmnoZXsomz3vGiWw+I9KMF9SVFOqZEemZekli1jN3U/UOqhHHvC6oWWGElhfSpGdOk6+O9prdwvtLj5BjRsQxdRnot+Zeifpy/2/0stktKTRNLmbk0mwXyl8253fyojj+8rxOHNAhjjm5n0/5OOCGOKBzkrMO0Z75lvSAzKlrF32Z/3z8BqLAn+yMV7VhAAAAAElFTkSuQmCC"; let image = atob(dataURI); const IMAGE_ARRAYBUFFER = Uint8Array.from(image, byte => byte.charCodeAt(0)).buffer; -add_task(function* test_contentscript() { +add_task(function* test_pageAction_withPopup() { function background() { // TODO: Use the Tabs API to obtain the tab ids for showing pageActions. let tabId = 1; @@ -56,12 +58,7 @@ add_task(function* test_contentscript() { browser.test.sendMessage("page-action-onClicked-fired"); }); - let extensionInfo = { - // Extract the assigned uuid from the background page url. - uuid: `{${window.location.hostname}}`, - }; - - browser.test.sendMessage("ready", extensionInfo); + browser.test.sendMessage("ready"); } function popupScript() { @@ -131,7 +128,7 @@ add_task(function* test_contentscript() { extension.sendMessage("page-action-enable-onClicked-listener"); yield extension.awaitMessage("page-action-onClicked-listener-enabled"); - clickPageAction(uuid); + PageActions.synthesizeClick(uuid); yield extension.awaitMessage("page-action-onClicked-fired"); extension.sendMessage("page-action-disable-onClicked-listener"); @@ -139,7 +136,7 @@ add_task(function* test_contentscript() { } else { ok(url.includes(name), "Calling pageAction.getPopup should return the correct popup URL when the popup is set."); - clickPageAction(uuid); + PageActions.synthesizeClick(uuid); let location = yield extension.awaitMessage("page-action-from-popup"); ok(location.includes(name), "The popup with the correct URL should be shown."); @@ -151,11 +148,12 @@ add_task(function* test_contentscript() { } yield extension.startup(); - let {uuid} = yield extension.awaitMessage("ready"); + yield extension.awaitMessage("ready"); + const uuid = `{${extension.uuid}}`; extension.sendMessage("page-action-show"); yield extension.awaitMessage("page-action-shown"); - ok(isPageActionShown(uuid), "The PageAction should be shown."); + ok(PageActions.isShown(uuid), "The PageAction should be shown."); yield testPopup("default.html", uuid); yield testPopup("a.html", uuid); @@ -163,7 +161,7 @@ add_task(function* test_contentscript() { yield testPopup("b.html", uuid); yield extension.unload(); - ok(!isPageActionShown(uuid), "The PageAction should be removed after unload."); + ok(!PageActions.isShown(uuid), "The PageAction should be removed after unload."); }); diff --git a/testing/specialpowers/content/SpecialPowersObserverAPI.js b/testing/specialpowers/content/SpecialPowersObserverAPI.js index a2c8185315a5..96488924d610 100644 --- a/testing/specialpowers/content/SpecialPowersObserverAPI.js +++ b/testing/specialpowers/content/SpecialPowersObserverAPI.js @@ -570,7 +570,7 @@ SpecialPowersObserverAPI.prototype = { let id = aMessage.data.id; let extension = this._extensions.get(id); extension.on("startup", () => { - this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionSetId", args: [extension.id]}); + this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionSetId", args: [extension.id, extension.uuid]}); }); // Make sure the extension passes the packaging checks when diff --git a/testing/specialpowers/content/specialpowersAPI.js b/testing/specialpowers/content/specialpowersAPI.js index e35968b1015a..535d144904af 100644 --- a/testing/specialpowers/content/specialpowersAPI.js +++ b/testing/specialpowers/content/specialpowersAPI.js @@ -2001,6 +2001,7 @@ SpecialPowersAPI.prototype = { resolveStartup(); } else if (msg.data.type == "extensionSetId") { extension.id = msg.data.args[0]; + extension.uuid = msg.data.args[1]; } else if (msg.data.type == "extensionFailed") { state = "failed"; rejectStartup("startup failed"); diff --git a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm index 9b6d8d9037b2..c6b813003e00 100644 --- a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm +++ b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm @@ -188,6 +188,7 @@ class ExtensionWrapper { if (extension) { this.id = extension.id; + this.uuid = extension.uuid; this.attachExtension(extension); } } From 57d63067b9730f3cbf261ab286ffb5586f5c55e7 Mon Sep 17 00:00:00 2001 From: Boris Chiou Date: Wed, 19 Apr 2017 22:44:42 -0500 Subject: [PATCH 07/65] servo: Merge #16536 - stylo: Change the animation_type of column-count to normal (from BorisChiou:stylo/animation/column_count); r=Manishearth According to PR #16494, column-count should be animatable, so we should change the animation_type to "normal". --- - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix Bug 1355732 and PR #16494. - [X] These changes do not require tests because we have tests in gecko already. Source-Repo: https://github.com/servo/servo Source-Revision: ac92bddbf5e4a8e2f68fc57883244f9c4a35d466 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : c3f546fc03f7380630bcb8966c2cfe1af5d12b85 --- servo/components/style/properties/longhand/column.mako.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servo/components/style/properties/longhand/column.mako.rs b/servo/components/style/properties/longhand/column.mako.rs index 89766b4ae5a5..fef81ca9ac4e 100644 --- a/servo/components/style/properties/longhand/column.mako.rs +++ b/servo/components/style/properties/longhand/column.mako.rs @@ -23,7 +23,7 @@ ${helpers.predefined_type("column-count", parse_method="parse_positive", initial_specified_value="Either::Second(Auto)", experimental="True", - animation_type="none", + animation_type="normal", extra_prefixes="moz", spec="https://drafts.csswg.org/css-multicol/#propdef-column-count")} From cb5df9876f08bb9fcaa616c4361079a0749194c3 Mon Sep 17 00:00:00 2001 From: KuoE0 Date: Wed, 19 Apr 2017 23:19:48 -0500 Subject: [PATCH 08/65] servo: Merge #16537 - Add `inline-axis` and `block-axis` aliases for `-moz-box-orient` (from KuoE0:add-inline-axis-and-block-axis-for-moz-box-orient); r=KuoE0 This issue is reported at https://bugzilla.mozilla.org/show_bug.cgi?id=1355005. spec: https://developer.mozilla.org/en-US/docs/Web/CSS/box-orient --- - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix [Bug 1355005](https://bugzilla.mozilla.org/show_bug.cgi?id=1355005) - [X] These changes do not require tests in Gecko. Source-Repo: https://github.com/servo/servo Source-Revision: f74f1fb59233c3f366cec4ace5df37c0264786be --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 0028688311e5bf2ca2cfee90dad07ba07ad85848 --- servo/components/style/properties/longhand/xul.mako.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/servo/components/style/properties/longhand/xul.mako.rs b/servo/components/style/properties/longhand/xul.mako.rs index f37809dadc80..b59c36f002d5 100644 --- a/servo/components/style/properties/longhand/xul.mako.rs +++ b/servo/components/style/properties/longhand/xul.mako.rs @@ -31,6 +31,7 @@ ${helpers.predefined_type("-moz-box-flex", "Number", "0.0", "parse_non_negative" ${helpers.single_keyword("-moz-box-orient", "horizontal vertical", products="gecko", gecko_ffi_name="mBoxOrient", + extra_gecko_aliases="inline-axis=horizontal block-axis=vertical", gecko_enum_prefix="StyleBoxOrient", animation_type="none", alias="-webkit-box-orient", From 4126cab5bb4acce0814a79b96fc9a05b4acd35c0 Mon Sep 17 00:00:00 2001 From: Astley Chen Date: Thu, 20 Apr 2017 13:16:42 +0800 Subject: [PATCH 09/65] Bug 1355752 - Remove B2G wording in AccessibleCaret. r=TYLin MozReview-Commit-ID: JOv2caZc8J0 --HG-- extra : rebase_source : 48a14052cc8dc0b3f7054465cec81ae322a59899 --- layout/base/AccessibleCaret.cpp | 2 +- layout/base/gtest/TestAccessibleCaretManager.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/layout/base/AccessibleCaret.cpp b/layout/base/AccessibleCaret.cpp index 06e135dc9588..cf176b6e5aa4 100644 --- a/layout/base/AccessibleCaret.cpp +++ b/layout/base/AccessibleCaret.cpp @@ -392,7 +392,7 @@ AccessibleCaret::GetZoomLevel() // Full zoom on desktop. float fullZoom = mPresShell->GetPresContext()->GetFullZoom(); - // Pinch-zoom on B2G or fennec. + // Pinch-zoom on fennec. float resolution = mPresShell->GetCumulativeResolution(); return fullZoom * resolution; diff --git a/layout/base/gtest/TestAccessibleCaretManager.cpp b/layout/base/gtest/TestAccessibleCaretManager.cpp index a6b25eb767b7..1d3a1c039404 100644 --- a/layout/base/gtest/TestAccessibleCaretManager.cpp +++ b/layout/base/gtest/TestAccessibleCaretManager.cpp @@ -350,7 +350,7 @@ TEST_F(AccessibleCaretManagerTester, TestTypingAtEndOfInput) TEST_F(AccessibleCaretManagerTester, TestScrollInSelectionMode) { - // Simulate B2G preference. + // Simulate caret hiding when scrolling. AutoRestore savesCaretsAlwaysShowWhenScrolling( MockAccessibleCaretManager::sCaretsAlwaysShowWhenScrolling); MockAccessibleCaretManager::sCaretsAlwaysShowWhenScrolling = false; @@ -534,7 +534,7 @@ TEST_F(AccessibleCaretManagerTester, TestScrollInSelectionModeWithAlwaysTiltPref TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeWhenLogicallyVisible) { - // Simulate B2G preference. + // Simulate caret hiding when scrolling. AutoRestore savesCaretsAlwaysShowWhenScrolling( MockAccessibleCaretManager::sCaretsAlwaysShowWhenScrolling); MockAccessibleCaretManager::sCaretsAlwaysShowWhenScrolling = false; @@ -599,7 +599,7 @@ TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeWhenLogicallyVisible) TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeWhenHidden) { - // Simulate B2G preference. + // Simulate caret hiding when scrolling. AutoRestore savesCaretsAlwaysShowWhenScrolling( MockAccessibleCaretManager::sCaretsAlwaysShowWhenScrolling); MockAccessibleCaretManager::sCaretsAlwaysShowWhenScrolling = false; @@ -658,7 +658,7 @@ TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeWhenHidden) TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeOnEmptyContent) { - // Simulate B2G preference. + // Simulate caret hiding when scrolling. AutoRestore savesCaretsAlwaysShowWhenScrolling( MockAccessibleCaretManager::sCaretsAlwaysShowWhenScrolling); MockAccessibleCaretManager::sCaretsAlwaysShowWhenScrolling = false; From e4081a158f9a8d0e5bc3e26121f7c08bd55dcf93 Mon Sep 17 00:00:00 2001 From: Astley Chen Date: Thu, 20 Apr 2017 13:16:42 +0800 Subject: [PATCH 10/65] Bug 1355752 - Remove B2G code from PresShell files. r=jrmuizel MozReview-Commit-ID: FIap9QM0vve --HG-- extra : rebase_source : f80c009d67293b74b4c645f0e013842c6098d8ad --- layout/base/PresShell.cpp | 15 +++++---------- layout/base/nsIPresShell.h | 4 ---- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp index 8fdbc711d0d3..23124a7ecaea 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -200,10 +200,6 @@ #include "mozilla/dom/ImageTracker.h" #include "nsIDocShellTreeOwner.h" -#ifdef MOZ_B2G -#include "nsIHardwareKeyHandler.h" -#endif - #ifdef MOZ_TASK_TRACER #include "GeckoTaskTracer.h" using namespace mozilla::tasktracer; @@ -6376,7 +6372,7 @@ PresShell::RecordShadowStyleChange(ShadowRoot* aShadowRoot) } void -PresShell::Paint(nsView* aViewToPaint, +PresShell::Paint(nsView* aViewToPaint, const nsRegion& aDirtyRegion, uint32_t aFlags) { @@ -6425,11 +6421,10 @@ PresShell::Paint(nsView* aViewToPaint, nsAutoNotifyDidPaint notifyDidPaint(this, aFlags); - // Whether or not we should set first paint when painting is - // suppressed is debatable. For now we'll do it because - // B2G relies on first paint to configure the viewport and - // we only want to do that when we have real content to paint. - // See Bug 798245 + // Whether or not we should set first paint when painting is suppressed + // is debatable. For now we'll do it because B2G relied on first paint + // to configure the viewport and we only want to do that when we have + // real content to paint. See Bug 798245 if (mIsFirstPaint && !mPaintingSuppressed) { layerManager->SetIsFirstPaint(); mIsFirstPaint = false; diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index 5f44b3029a41..67dc798014ee 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -51,10 +51,6 @@ #include "nsFrameState.h" #include "Units.h" -#ifdef MOZ_B2G -#include "nsIHardwareKeyHandler.h" -#endif - class nsDocShell; class nsIDocument; class nsIFrame; From 18d66f87fd81cbec29ed1dbd10e9f9e0418e13e8 Mon Sep 17 00:00:00 2001 From: Astley Chen Date: Thu, 20 Apr 2017 13:16:43 +0800 Subject: [PATCH 11/65] Bug 1355752 - Remove B2G code from nsCSSFrameConstructor.cpp. r=dholbert MozReview-Commit-ID: Kvzn02nmzb0 --HG-- extra : rebase_source : d70db09f85cbb34cf5fc0fa05c0db3072ca911f5 --- layout/base/nsCSSFrameConstructor.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 642c239eaf77..782cd8339728 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -3698,8 +3698,8 @@ nsCSSFrameConstructor::FindInputData(Element* aElement, nsCSSAnonBoxes::buttonContent) }, // TODO: this is temporary until a frame is written: bug 635240. SIMPLE_INT_CREATE(NS_FORM_INPUT_NUMBER, NS_NewNumberControlFrame), -#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) - // On Android/B2G, date/time input appears as a normal text box. +#if defined(MOZ_WIDGET_ANDROID) + // On Android, date/time input appears as a normal text box. SIMPLE_INT_CREATE(NS_FORM_INPUT_TIME, NS_NewTextControlFrame), SIMPLE_INT_CREATE(NS_FORM_INPUT_DATE, NS_NewTextControlFrame), #else @@ -3730,10 +3730,10 @@ nsCSSFrameConstructor::FindInputData(Element* aElement, auto controlType = control->ControlType(); - // Note that Android/Gonk widgets don't have theming support and thus + // Note that Android widgets don't have theming support and thus // appearance:none is the same as any other appearance value. // So this chunk doesn't apply there: -#if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_GONK) +#if !defined(MOZ_WIDGET_ANDROID) // radio and checkbox inputs with appearance:none should be constructed // by display type. (Note that we're not checking that appearance is // not (respectively) NS_THEME_RADIO and NS_THEME_CHECKBOX.) From 1c6ca32418d503cb8070211d691284d9d25b5f7a Mon Sep 17 00:00:00 2001 From: Astley Chen Date: Thu, 20 Apr 2017 13:16:43 +0800 Subject: [PATCH 12/65] Bug 1355752 - Remove B2G code from layout/build files. r=jmaher MozReview-Commit-ID: 4VYUKm8MgHb --HG-- extra : rebase_source : e7619fffc64736443b6b7fc5f0833b62538db8b2 --- layout/build/nsLayoutModule.cpp | 96 -------------------------------- layout/build/nsLayoutStatics.cpp | 9 --- 2 files changed, 105 deletions(-) diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index d6413ace24ea..24e2eddfc4f0 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -100,20 +100,6 @@ #include "mozilla/dom/nsSynthVoiceRegistry.h" #endif -#ifdef MOZ_WIDGET_GONK -#include "SystemWorkerManager.h" -using mozilla::dom::gonk::SystemWorkerManager; -#define SYSTEMWORKERMANAGER_CID \ - {0xd53b6524, 0x6ac3, 0x42b0, {0xae, 0xca, 0x62, 0xb3, 0xc4, 0xe5, 0x2b, 0x04}} -#endif - -#ifdef MOZ_WIDGET_GONK -#include "AudioManager.h" -using mozilla::dom::gonk::AudioManager; -#include "nsVolumeService.h" -using mozilla::system::nsVolumeService; -#endif - #include "mozilla/dom/PushNotifier.h" using mozilla::dom::PushNotifier; #define PUSHNOTIFIER_CID \ @@ -135,11 +121,9 @@ using mozilla::dom::AudioChannelAgent; #include "SystemPrincipal.h" #include "NullPrincipal.h" #include "nsNetCID.h" -#ifndef MOZ_WIDGET_GONK #if defined(MOZ_WIDGET_ANDROID) #include "nsHapticFeedback.h" #endif -#endif #include "nsParserUtils.h" #include "nsHTMLCanvasFrame.h" @@ -201,9 +185,6 @@ static void Shutdown(); #include "nsIPresentationService.h" -#ifdef MOZ_WIDGET_GONK -#include "GonkGPSGeolocationProvider.h" -#endif #include "MediaManager.h" #include "GMPService.h" @@ -286,30 +267,18 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(ServiceWorkerManager, NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(WorkerDebuggerManager, WorkerDebuggerManager::GetInstance) -#ifdef MOZ_WIDGET_GONK -NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(SystemWorkerManager, - SystemWorkerManager::FactoryCreate) -#endif - #ifdef MOZ_WEBSPEECH NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSynthVoiceRegistry, nsSynthVoiceRegistry::GetInstanceForService) #endif -#ifdef MOZ_WIDGET_GONK -NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AudioManager, - AudioManager::GetInstance) -#endif - NS_GENERIC_FACTORY_CONSTRUCTOR(AudioChannelAgent) NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceSensors) -#ifndef MOZ_WIDGET_GONK #if defined(ANDROID) NS_GENERIC_FACTORY_CONSTRUCTOR(nsHapticFeedback) #endif -#endif NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ThirdPartyUtil, Init) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIPowerManagerService, PowerManagerService::GetInstance) @@ -318,16 +287,6 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsITimeService, NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIStreamingProtocolControllerService, StreamingProtocolControllerService::GetInstance) -#ifdef MOZ_WIDGET_GONK -#ifndef DISABLE_MOZ_RIL_GEOLOC -NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIGeolocationProvider, - GonkGPSGeolocationProvider::GetSingleton) -#endif -// Since the nsVolumeService constructor calls into nsIPowerManagerService, -// we need it to be constructed sometime after nsIPowerManagerService. -NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsVolumeService, - nsVolumeService::GetSingleton) -#endif NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIMediaManagerService, MediaManager::GetInstance) NS_GENERIC_FACTORY_CONSTRUCTOR(PresentationDeviceManager) @@ -700,18 +659,8 @@ NS_DEFINE_NAMED_CID(QUOTAMANAGER_SERVICE_CID); NS_DEFINE_NAMED_CID(SERVICEWORKERMANAGER_CID); NS_DEFINE_NAMED_CID(NOTIFICATIONTELEMETRYSERVICE_CID); NS_DEFINE_NAMED_CID(PUSHNOTIFIER_CID); - NS_DEFINE_NAMED_CID(WORKERDEBUGGERMANAGER_CID); -#ifdef MOZ_WIDGET_GONK -NS_DEFINE_NAMED_CID(SYSTEMWORKERMANAGER_CID); -#endif -#ifdef MOZ_WIDGET_GONK -NS_DEFINE_NAMED_CID(NS_AUDIOMANAGER_CID); -NS_DEFINE_NAMED_CID(NS_VOLUMESERVICE_CID); -#endif - NS_DEFINE_NAMED_CID(NS_AUDIOCHANNELAGENT_CID); - NS_DEFINE_NAMED_CID(NS_HTMLEDITOR_CID); NS_DEFINE_NAMED_CID(NS_EDITORCONTROLLER_CID); NS_DEFINE_NAMED_CID(NS_EDITINGCONTROLLER_CID); @@ -739,17 +688,9 @@ NS_DEFINE_NAMED_CID(NS_NULLPRINCIPAL_CID); NS_DEFINE_NAMED_CID(THIRDPARTYUTIL_CID); NS_DEFINE_NAMED_CID(NS_STRUCTUREDCLONECONTAINER_CID); NS_DEFINE_NAMED_CID(NS_DEVICE_SENSORS_CID); - -#ifndef MOZ_WIDGET_GONK #if defined(ANDROID) NS_DEFINE_NAMED_CID(NS_HAPTICFEEDBACK_CID); #endif -#endif -#ifndef DISABLE_MOZ_RIL_GEOLOC -#ifdef MOZ_WIDGET_GONK -NS_DEFINE_NAMED_CID(GONK_GPS_GEOLOCATION_PROVIDER_CID); -#endif -#endif NS_DEFINE_NAMED_CID(NS_POWERMANAGERSERVICE_CID); NS_DEFINE_NAMED_CID(OSFILECONSTANTSSERVICE_CID); NS_DEFINE_NAMED_CID(UDPSOCKETCHILD_CID); @@ -778,10 +719,6 @@ NS_DEFINE_NAMED_CID(PRESENTATION_TCP_SESSION_TRANSPORT_CID); NS_DEFINE_NAMED_CID(TEXT_INPUT_PROCESSOR_CID); -#ifdef MOZ_B2G -NS_DEFINE_NAMED_CID(NS_HARDWARE_KEY_HANDLER_CID); -#endif - NS_DEFINE_NAMED_CID(NS_SCRIPTERROR_CID); static nsresult @@ -989,13 +926,6 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = { { &kNOTIFICATIONTELEMETRYSERVICE_CID, false, nullptr, NotificationTelemetryServiceConstructor }, { &kPUSHNOTIFIER_CID, false, nullptr, PushNotifierConstructor }, { &kWORKERDEBUGGERMANAGER_CID, true, nullptr, WorkerDebuggerManagerConstructor }, -#ifdef MOZ_WIDGET_GONK - { &kSYSTEMWORKERMANAGER_CID, true, nullptr, SystemWorkerManagerConstructor }, -#endif -#ifdef MOZ_WIDGET_GONK - { &kNS_AUDIOMANAGER_CID, true, nullptr, AudioManagerConstructor }, - { &kNS_VOLUMESERVICE_CID, true, nullptr, nsVolumeServiceConstructor }, -#endif { &kNS_AUDIOCHANNELAGENT_CID, true, nullptr, AudioChannelAgentConstructor }, { &kNS_HTMLEDITOR_CID, false, nullptr, HTMLEditorConstructor }, { &kNS_EDITORCONTROLLER_CID, false, nullptr, EditorControllerConstructor }, @@ -1031,10 +961,8 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = { { &kNS_SYSTEMPRINCIPAL_CID, false, nullptr, SystemPrincipalConstructor }, { &kNS_NULLPRINCIPAL_CID, false, nullptr, NullPrincipalConstructor }, { &kNS_DEVICE_SENSORS_CID, false, nullptr, nsDeviceSensorsConstructor }, -#ifndef MOZ_WIDGET_GONK #if defined(ANDROID) { &kNS_HAPTICFEEDBACK_CID, false, nullptr, nsHapticFeedbackConstructor }, -#endif #endif { &kTHIRDPARTYUTIL_CID, false, nullptr, ThirdPartyUtilConstructor }, { &kNS_STRUCTUREDCLONECONTAINER_CID, false, nullptr, nsStructuredCloneContainerConstructor }, @@ -1044,9 +972,6 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = { { &kGECKO_MEDIA_PLUGIN_SERVICE_CID, true, nullptr, GeckoMediaPluginServiceConstructor }, { &kNS_TIMESERVICE_CID, false, nullptr, nsITimeServiceConstructor }, { &kNS_MEDIASTREAMCONTROLLERSERVICE_CID, false, nullptr, nsIStreamingProtocolControllerServiceConstructor }, -#if defined(MOZ_WIDGET_GONK) && !defined(DISABLE_MOZ_RIL_GEOLOC) - { &kGONK_GPS_GEOLOCATION_PROVIDER_CID, false, nullptr, nsIGeolocationProviderConstructor }, -#endif { &kNS_MEDIAMANAGERSERVICE_CID, false, nullptr, nsIMediaManagerServiceConstructor }, #ifdef ACCESSIBILITY { &kNS_ACCESSIBILITY_SERVICE_CID, false, nullptr, CreateA11yService }, @@ -1134,13 +1059,6 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = { { NOTIFICATIONTELEMETRYSERVICE_CONTRACTID, &kNOTIFICATIONTELEMETRYSERVICE_CID }, { PUSHNOTIFIER_CONTRACTID, &kPUSHNOTIFIER_CID }, { WORKERDEBUGGERMANAGER_CONTRACTID, &kWORKERDEBUGGERMANAGER_CID }, -#ifdef MOZ_WIDGET_GONK - { SYSTEMWORKERMANAGER_CONTRACTID, &kSYSTEMWORKERMANAGER_CID }, -#endif -#ifdef MOZ_WIDGET_GONK - { NS_AUDIOMANAGER_CONTRACTID, &kNS_AUDIOMANAGER_CID }, - { NS_VOLUMESERVICE_CONTRACTID, &kNS_VOLUMESERVICE_CID }, -#endif { NS_AUDIOCHANNELAGENT_CONTRACTID, &kNS_AUDIOCHANNELAGENT_CID }, { "@mozilla.org/editor/htmleditor;1", &kNS_HTMLEDITOR_CID }, { "@mozilla.org/editor/editorcontroller;1", &kNS_EDITORCONTROLLER_CID }, @@ -1175,10 +1093,8 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = { { NS_SYSTEMPRINCIPAL_CONTRACTID, &kNS_SYSTEMPRINCIPAL_CID }, { NS_NULLPRINCIPAL_CONTRACTID, &kNS_NULLPRINCIPAL_CID }, { NS_DEVICE_SENSORS_CONTRACTID, &kNS_DEVICE_SENSORS_CID }, -#ifndef MOZ_WIDGET_GONK #if defined(ANDROID) { "@mozilla.org/widget/hapticfeedback;1", &kNS_HAPTICFEEDBACK_CID }, -#endif #endif { THIRDPARTYUTIL_CONTRACTID, &kTHIRDPARTYUTIL_CID }, { NS_STRUCTUREDCLONECONTAINER_CONTRACTID, &kNS_STRUCTUREDCLONECONTAINER_CID }, @@ -1187,9 +1103,6 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = { { "@mozilla.org/udp-socket-child;1", &kUDPSOCKETCHILD_CID }, { TIMESERVICE_CONTRACTID, &kNS_TIMESERVICE_CID }, { MEDIASTREAMCONTROLLERSERVICE_CONTRACTID, &kNS_MEDIASTREAMCONTROLLERSERVICE_CID }, -#if defined(MOZ_WIDGET_GONK) && !defined(DISABLE_MOZ_RIL_GEOLOC) - { GONK_GPS_GEOLOCATION_PROVIDER_CONTRACTID, &kGONK_GPS_GEOLOCATION_PROVIDER_CID }, -#endif { MEDIAMANAGERSERVICE_CONTRACTID, &kNS_MEDIAMANAGERSERVICE_CID }, #ifdef ACCESSIBILITY { "@mozilla.org/accessibilityService;1", &kNS_ACCESSIBILITY_SERVICE_CID }, @@ -1200,9 +1113,6 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = { { PRESENTATION_DEVICE_MANAGER_CONTRACTID, &kPRESENTATION_DEVICE_MANAGER_CID }, { PRESENTATION_TCP_SESSION_TRANSPORT_CONTRACTID, &kPRESENTATION_TCP_SESSION_TRANSPORT_CID }, { "@mozilla.org/text-input-processor;1", &kTEXT_INPUT_PROCESSOR_CID }, -#ifdef MOZ_B2G - { NS_HARDWARE_KEY_HANDLER_CONTRACTID, &kNS_HARDWARE_KEY_HANDLER_CID }, -#endif { NS_SCRIPTERROR_CONTRACTID, &kNS_SCRIPTERROR_CID }, { nullptr } }; @@ -1219,13 +1129,7 @@ static const mozilla::Module::CategoryEntry kLayoutCategories[] = { { "app-startup", "Push Notifier", "service," PUSHNOTIFIER_CONTRACTID }, { "clear-origin-attributes-data", "QuotaManagerService", "service," QUOTAMANAGER_SERVICE_CONTRACTID }, { OBSERVER_TOPIC_IDLE_DAILY, "QuotaManagerService", QUOTAMANAGER_SERVICE_CONTRACTID }, -#ifdef MOZ_WIDGET_GONK - { "app-startup", "Volume Service", "service," NS_VOLUMESERVICE_CONTRACTID }, -#endif CONTENTDLF_CATEGORIES -#ifdef MOZ_WIDGET_GONK - { "profile-after-change", "Gonk System Worker Manager", SYSTEMWORKERMANAGER_CONTRACTID }, -#endif { "profile-after-change", "PresentationDeviceManager", PRESENTATION_DEVICE_MANAGER_CONTRACTID }, { "profile-after-change", "PresentationService", PRESENTATION_SERVICE_CONTRACTID }, { "profile-after-change", "Notification Telemetry Service", NOTIFICATIONTELEMETRYSERVICE_CONTRACTID }, diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp index a0686e6ca9c4..166e47293346 100644 --- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -102,11 +102,6 @@ #include "Latency.h" #include "WebAudioUtils.h" -#ifdef MOZ_WIDGET_GONK -#include "nsVolumeService.h" -using namespace mozilla::system; -#endif - #include "nsError.h" #include "nsJSEnvironment.h" @@ -402,10 +397,6 @@ nsLayoutStatics::Shutdown() AsyncLatencyLogger::ShutdownLogger(); WebAudioUtils::Shutdown(); -#ifdef MOZ_WIDGET_GONK - nsVolumeService::Shutdown(); -#endif - #ifdef MOZ_WEBSPEECH nsSynthVoiceRegistry::Shutdown(); #endif From bc4e66e6023d2e553288cd7cd417a937d9c63ea8 Mon Sep 17 00:00:00 2001 From: Astley Chen Date: Thu, 20 Apr 2017 13:16:43 +0800 Subject: [PATCH 13/65] Bug 1355752 - Remove B2G code from nsFormControlFrame.cpp & forms.css. r=dholbert MozReview-Commit-ID: I1PeSxMLFbn --HG-- extra : rebase_source : eafb99a5df41053e7ea51b8d9529b6a343152cfd --- layout/forms/nsFormControlFrame.cpp | 6 +++--- layout/style/res/forms.css | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/layout/forms/nsFormControlFrame.cpp b/layout/forms/nsFormControlFrame.cpp index 7290d875e8f7..eadd90afec02 100644 --- a/layout/forms/nsFormControlFrame.cpp +++ b/layout/forms/nsFormControlFrame.cpp @@ -49,7 +49,7 @@ nsFormControlFrame::GetMinISize(nsRenderingContext *aRenderingContext) { nscoord result; DISPLAY_MIN_WIDTH(this, result); -#if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_GONK) +#if !defined(MOZ_WIDGET_ANDROID) result = StyleDisplay()->UsedAppearance() == NS_THEME_NONE ? 0 : DefaultSize(); #else result = DefaultSize(); @@ -62,7 +62,7 @@ nsFormControlFrame::GetPrefISize(nsRenderingContext *aRenderingContext) { nscoord result; DISPLAY_PREF_WIDTH(this, result); -#if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_GONK) +#if !defined(MOZ_WIDGET_ANDROID) result = StyleDisplay()->UsedAppearance() == NS_THEME_NONE ? 0 : DefaultSize(); #else result = DefaultSize(); @@ -82,7 +82,7 @@ nsFormControlFrame::ComputeAutoSize(nsRenderingContext* aRC, ComputeSizeFlags aFlags) { LogicalSize size(aWM, 0, 0); -#if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_GONK) +#if !defined(MOZ_WIDGET_ANDROID) if (StyleDisplay()->UsedAppearance() == NS_THEME_NONE) { return size; } diff --git a/layout/style/res/forms.css b/layout/style/res/forms.css index 5f6310d02665..6e156b25a2a4 100644 --- a/layout/style/res/forms.css +++ b/layout/style/res/forms.css @@ -598,7 +598,7 @@ input[type="checkbox"]:disabled:hover:active { cursor: inherit; } -%if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) +%if defined(MOZ_WIDGET_ANDROID) /* * These platforms doesn't have any theming support and thus appearance:none * is the same as any other appearance value. @@ -677,7 +677,7 @@ input[type="checkbox"]:indeterminate:disabled { background-image: url(indeterminate-checkmark.svg#disabled); } -%endif /* defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK) */ +%endif /* defined(MOZ_WIDGET_ANDROID) */ % On Mac, the native theme takes care of this. % See nsNativeThemeCocoa::ThemeDrawsFocusForWidget. From 8713e7a155ae9ce93410811fa57a4b3b82b735d1 Mon Sep 17 00:00:00 2001 From: Astley Chen Date: Thu, 20 Apr 2017 13:16:43 +0800 Subject: [PATCH 14/65] Bug 1355752 - Remove B2G code from nsGfxScrollFrame.cpp. r=kats MozReview-Commit-ID: 6ePwT9UWJIJ --HG-- extra : rebase_source : 0b73e647867448a6b8a81074d7fc4410645b6eed --- layout/generic/nsGfxScrollFrame.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 9e5efeab80bd..79f6f6150263 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -1268,7 +1268,7 @@ ScrollFrameHelper::HandleScrollbarStyleSwitching() } } -#if defined(MOZ_B2G) || defined(MOZ_WIDGET_ANDROID) +#if defined(MOZ_WIDGET_ANDROID) static bool IsFocused(nsIContent* aContent) { // Some content elements, like the GetContent() of a scroll frame @@ -1317,7 +1317,7 @@ ScrollFrameHelper::WantAsyncScroll() const bool isHScrollable = (scrollRange.width >= oneDevPixel) && (styles.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN); -#if defined(MOZ_B2G) || defined(MOZ_WIDGET_ANDROID) +#if defined(MOZ_WIDGET_ANDROID) // Mobile platforms need focus to scroll. bool canScrollWithoutScrollbars = IsFocused(mOuter->GetContent()); #else From f93fc0a7bcf79f5c730eec2eb95ff831b01ef69f Mon Sep 17 00:00:00 2001 From: Astley Chen Date: Thu, 20 Apr 2017 13:16:43 +0800 Subject: [PATCH 15/65] Bug 1355752 - Remove B2G code from FrameLayerBuilder.cpp. r=mstange MozReview-Commit-ID: CbMnZJldiUl --HG-- extra : rebase_source : 4899991aedc8cc2413fcf695601eb79c0245eb01 --- layout/painting/FrameLayerBuilder.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/layout/painting/FrameLayerBuilder.cpp b/layout/painting/FrameLayerBuilder.cpp index 61005f9e273f..0569a023fbab 100644 --- a/layout/painting/FrameLayerBuilder.cpp +++ b/layout/painting/FrameLayerBuilder.cpp @@ -2339,15 +2339,7 @@ ContainerState::GetLayerCreationHint(AnimatedGeometryRoot* aAnimatedGeometryRoot break; } nsIScrollableFrame* scrollable = do_QueryFrame(fParent); - if (scrollable - #ifdef MOZ_B2G - && scrollable->WantAsyncScroll() - #endif - ) { - // WantAsyncScroll() returns false when the frame has overflow:hidden, - // so we won't create tiled layers for overflow:hidden frames even if - // they have a display port. The main purpose of the WantAsyncScroll check - // is to allow the B2G camera app to use hardware composer for compositing. + if (scrollable) { return LayerManager::SCROLLABLE; } } From 4414bd44eb0e94f80e29e6a6e43f4fdf5e53d63a Mon Sep 17 00:00:00 2001 From: Henri Sivonen Date: Thu, 13 Apr 2017 14:08:35 +0300 Subject: [PATCH 16/65] Bug 1356181 - Gather telemetry about isindex usage in hope of justifying removal. r=Ehsan,francois MozReview-Commit-ID: 9dDVvgxxZml --HG-- extra : rebase_source : c78e97a5b1bcd1d322ba1381657ed9bd3e814f11 --- dom/html/HTMLFormSubmission.cpp | 2 ++ toolkit/components/telemetry/Histograms.json | 7 +++++++ toolkit/components/telemetry/histogram-whitelists.json | 1 + 3 files changed, 10 insertions(+) diff --git a/dom/html/HTMLFormSubmission.cpp b/dom/html/HTMLFormSubmission.cpp index d6269a7cab49..ee67c340a8bf 100644 --- a/dom/html/HTMLFormSubmission.cpp +++ b/dom/html/HTMLFormSubmission.cpp @@ -35,6 +35,7 @@ #include "nsCExternalHandlerService.h" #include "nsIFileStreams.h" #include "nsContentUtils.h" +#include "mozilla/Telemetry.h" #include "mozilla/dom/Directory.h" #include "mozilla/dom/EncodingUtils.h" @@ -188,6 +189,7 @@ FSURLEncoded::AddIsindex(const nsAString& aValue) // Append data to string if (mQueryString.IsEmpty()) { + Telemetry::Accumulate(Telemetry::FORM_ISINDEX_USED, true); mQueryString.Assign(convValue); } else { mQueryString += NS_LITERAL_CSTRING("&isindex=") + convValue; diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index f341d8dc16bc..a70edcc4fce3 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -5917,6 +5917,13 @@ "kind": "boolean", "description": "Deleted or to-be-reused innerwindow which has had mutation event listeners." }, + "FORM_ISINDEX_USED": { + "alert_emails": ["hsivonen@mozilla.com"], + "expires_in_version": "56", + "kind": "flag", + "bug_numbers": [1356181], + "description": "Whether there has been an isindex form submission in this session." + }, "CHARSET_OVERRIDE_SITUATION": { "expires_in_version": "never", "kind": "enumerated", diff --git a/toolkit/components/telemetry/histogram-whitelists.json b/toolkit/components/telemetry/histogram-whitelists.json index 1fb6becbf747..17a634f2b44c 100644 --- a/toolkit/components/telemetry/histogram-whitelists.json +++ b/toolkit/components/telemetry/histogram-whitelists.json @@ -1981,6 +1981,7 @@ "FX_TOUCH_USED", "GEOLOCATION_ERROR", "JS_TELEMETRY_ADDON_EXCEPTIONS", + "FORM_ISINDEX_USED", "MASTER_PASSWORD_ENABLED", "MEDIA_CODEC_USED", "MEDIA_DECODING_PROCESS_CRASH", From 40a6a08486b546d0f269822ab926147a80bcd44f Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 13 Apr 2017 13:25:01 +0800 Subject: [PATCH 17/65] Bug 1355427 - Part 3: stylo: Update test expectations; r=heycam MozReview-Commit-ID: AOHzrajCUVz --- layout/reftests/bugs/reftest-stylo.list | 4 +- layout/reftests/mathml/reftest-stylo.list | 144 +++++++++++----------- 2 files changed, 74 insertions(+), 74 deletions(-) diff --git a/layout/reftests/bugs/reftest-stylo.list b/layout/reftests/bugs/reftest-stylo.list index 0efd2852eb35..e4da8028f58a 100644 --- a/layout/reftests/bugs/reftest-stylo.list +++ b/layout/reftests/bugs/reftest-stylo.list @@ -461,7 +461,7 @@ fails == 345267-1a.html 345267-1a.html fails == 345267-1b.html 345267-1b.html fails == 345267-1c.html 345267-1c.html fails == 345267-1d.html 345267-1d.html -fails == 345563-sub.xhtml 345563-sub.xhtml +== 345563-sub.xhtml 345563-sub.xhtml == 346189-1.xul 346189-1.xul fails == 346774-1a.html 346774-1a.html fails == 346774-1b.html 346774-1b.html @@ -981,7 +981,7 @@ fails == 412352-2.html 412352-2.html fails == 413840-pushed-line-bullet.html 413840-pushed-line-bullet.html == 413840-bullet-first-line.html 413840-bullet-first-line.html == 413982.html 413982.html -fails == 414123.xhtml 414123.xhtml +== 414123.xhtml 414123.xhtml == 414638.html 414638.html fails == 414851-1.html 414851-1.html fails == 416106-1.xhtml 416106-1.xhtml diff --git a/layout/reftests/mathml/reftest-stylo.list b/layout/reftests/mathml/reftest-stylo.list index b6920c6688ee..11d9fb1e2406 100644 --- a/layout/reftests/mathml/reftest-stylo.list +++ b/layout/reftests/mathml/reftest-stylo.list @@ -6,8 +6,8 @@ random-if(gtkWidget) == dir-3.html dir-3.html == dir-5.html dir-5.html fails == dir-6.html dir-6.html fails == dir-6a.html dir-6a.html -fails == dir-7.html dir-7.html -fails == dir-8.html dir-8.html +== dir-7.html dir-7.html +== dir-8.html dir-8.html == dir-9.html dir-9.html == dir-10.html dir-10.html == dir-11.html dir-11.html @@ -15,8 +15,8 @@ fails == dir-8.html dir-8.html fails pref(mathml.disabled,true) == disabled-scriptlevel-1.html disabled-scriptlevel-1.html # bug 1339711 fails pref(mathml.disabled,true) == disabled-scriptlevel-1.xhtml disabled-scriptlevel-1.xhtml # bug 1339711 fails == displaystyle-1.html displaystyle-1.html -fails == displaystyle-2.html displaystyle-2.html -fails == displaystyle-3.html displaystyle-3.html +== displaystyle-2.html displaystyle-2.html +== displaystyle-3.html displaystyle-3.html fails == displaystyle-4.html displaystyle-4.html == mirror-op-1.html mirror-op-1.html == mirror-op-2.html mirror-op-2.html @@ -24,7 +24,7 @@ fails == displaystyle-4.html displaystyle-4.html == mirror-op-4.html mirror-op-4.html == dynamic-mi.xhtml dynamic-mi.xhtml == mphantom-1.html mphantom-1.html -fails == mphantom-2.html mphantom-2.html +== mphantom-2.html mphantom-2.html == mfenced-1.xhtml mfenced-1.xhtml == mfenced-2a.xhtml mfenced-2a.xhtml == mfenced-2b.xhtml mfenced-2b.xhtml @@ -52,43 +52,43 @@ fails == mfenced-10.html mfenced-10.html == overbar-width-1.xhtml overbar-width-1.xhtml == quotes-1.xhtml quotes-1.xhtml == stretchy-underbar-1.xhtml stretchy-underbar-1.xhtml -fails == stretchy-munderover-1a.html stretchy-munderover-1a.html -fails == stretchy-munderover-1b.html stretchy-munderover-1b.html -fails == stretchy-munderover-1c.html stretchy-munderover-1c.html -fails == stretchy-munderover-1d.html stretchy-munderover-1d.html -fails == stretchy-munderover-1e.html stretchy-munderover-1e.html -fails == stretchy-munderover-2a.html stretchy-munderover-2a.html -fails == stretchy-munderover-2b.html stretchy-munderover-2b.html -fails == stretchy-munderover-2c.html stretchy-munderover-2c.html -fails == stretchy-munderover-2d.html stretchy-munderover-2d.html -fails == stretchy-munderover-2e.html stretchy-munderover-2e.html -fails == stretchy-munderover-2f.html stretchy-munderover-2f.html -fails == stretchy-munderover-2g.html stretchy-munderover-2g.html -fails == stretchy-munderover-3a.html stretchy-munderover-3a.html -fails == stretchy-munderover-3b.html stretchy-munderover-3b.html -fails == stretchy-munderover-3c.html stretchy-munderover-3c.html -fails == stretchy-munderover-3d.html stretchy-munderover-3d.html -fails == stretchy-msup-1a.html stretchy-msup-1a.html -fails == stretchy-msup-1b.html stretchy-msup-1b.html -fails == stretchy-msup-1c.html stretchy-msup-1c.html -fails == stretchy-msup-1d.html stretchy-msup-1d.html -fails == stretchy-mfenced-1a.html stretchy-mfenced-1a.html -fails == stretchy-mfenced-1b.html stretchy-mfenced-1b.html -fails == stretchy-mfenced-2a.html stretchy-mfenced-2a.html -fails == stretchy-mfenced-2b.html stretchy-mfenced-2b.html -fails == stretchy-mfenced-3a.html stretchy-mfenced-3a.html -fails == stretchy-mfenced-3b.html stretchy-mfenced-3b.html -fails == stretchy-mfenced-4a.html stretchy-mfenced-4a.html -fails == stretchy-mfenced-4b.html stretchy-mfenced-4b.html -fails == stretchy-mover-1a.html stretchy-mover-1a.html -fails == stretchy-mover-1b.html stretchy-mover-1b.html -fails == stretchy-mover-2a.html stretchy-mover-2a.html -fails == stretchy-mover-2b.html stretchy-mover-2b.html -fails == stretchy-mover-3.html stretchy-mover-3.html +== stretchy-munderover-1a.html stretchy-munderover-1a.html +== stretchy-munderover-1b.html stretchy-munderover-1b.html +== stretchy-munderover-1c.html stretchy-munderover-1c.html +== stretchy-munderover-1d.html stretchy-munderover-1d.html +== stretchy-munderover-1e.html stretchy-munderover-1e.html +== stretchy-munderover-2a.html stretchy-munderover-2a.html +== stretchy-munderover-2b.html stretchy-munderover-2b.html +== stretchy-munderover-2c.html stretchy-munderover-2c.html +== stretchy-munderover-2d.html stretchy-munderover-2d.html +== stretchy-munderover-2e.html stretchy-munderover-2e.html +== stretchy-munderover-2f.html stretchy-munderover-2f.html +== stretchy-munderover-2g.html stretchy-munderover-2g.html +== stretchy-munderover-3a.html stretchy-munderover-3a.html +== stretchy-munderover-3b.html stretchy-munderover-3b.html +== stretchy-munderover-3c.html stretchy-munderover-3c.html +== stretchy-munderover-3d.html stretchy-munderover-3d.html +== stretchy-msup-1a.html stretchy-msup-1a.html +== stretchy-msup-1b.html stretchy-msup-1b.html +== stretchy-msup-1c.html stretchy-msup-1c.html +== stretchy-msup-1d.html stretchy-msup-1d.html +== stretchy-mfenced-1a.html stretchy-mfenced-1a.html +== stretchy-mfenced-1b.html stretchy-mfenced-1b.html +== stretchy-mfenced-2a.html stretchy-mfenced-2a.html +== stretchy-mfenced-2b.html stretchy-mfenced-2b.html +== stretchy-mfenced-3a.html stretchy-mfenced-3a.html +== stretchy-mfenced-3b.html stretchy-mfenced-3b.html +== stretchy-mfenced-4a.html stretchy-mfenced-4a.html +== stretchy-mfenced-4b.html stretchy-mfenced-4b.html +== stretchy-mover-1a.html stretchy-mover-1a.html +== stretchy-mover-1b.html stretchy-mover-1b.html +== stretchy-mover-2a.html stretchy-mover-2a.html +== stretchy-mover-2b.html stretchy-mover-2b.html +== stretchy-mover-3.html stretchy-mover-3.html == stretchy-largeop-1.html stretchy-largeop-1.html fails == stretchy-largeop-2.html stretchy-largeop-2.html == stretchy-largeop-3.html stretchy-largeop-3.html -fails == table-width-1.xhtml table-width-1.xhtml +== table-width-1.xhtml table-width-1.xhtml == table-width-2.html table-width-2.html fails == table-width-3.html table-width-3.html == table-width-4.html table-width-4.html @@ -126,9 +126,9 @@ fails-if(http.oscpu=="Linux\u0020x86_64") random-if(winWidget&&!/^Windows\x20NT\ == mathbackground-2.xml mathbackground-2.xml == mathbackground-3.xml mathbackground-3.xml == mathbackground-4.xml mathbackground-4.xml -fails == mstyle-1.xhtml mstyle-1.xhtml -fails == mstyle-2.xhtml mstyle-2.xhtml -fails == mstyle-3.xhtml mstyle-3.xhtml +== mstyle-1.xhtml mstyle-1.xhtml +== mstyle-2.xhtml mstyle-2.xhtml +== mstyle-3.xhtml mstyle-3.xhtml == mstyle-4.xhtml mstyle-4.xhtml == mstyle-5.xhtml mstyle-5.xhtml == scale-stretchy-1.xhtml scale-stretchy-1.xhtml @@ -148,20 +148,20 @@ fails == stretchy-1.html stretchy-1.html random-if(gtkWidget) == mpadded-7.html mpadded-7.html random-if(gtkWidget) == mpadded-8.html mpadded-8.html random-if(gtkWidget) == mpadded-9.html mpadded-9.html -fails == math-display.html math-display.html +== math-display.html math-display.html fails == scriptlevel-1.html scriptlevel-1.html -fails == scriptlevel-movablelimits-1.html scriptlevel-movablelimits-1.html +== scriptlevel-movablelimits-1.html scriptlevel-movablelimits-1.html == munderover-align-accent-false.html munderover-align-accent-false.html == munderover-align-accent-true.html munderover-align-accent-true.html == munder-mover-align-accent-true.html munder-mover-align-accent-true.html == munder-mover-align-accent-false.html munder-mover-align-accent-false.html -fails == mfrac-linethickness-1.xhtml mfrac-linethickness-1.xhtml -fails == mfrac-linethickness-2.xhtml mfrac-linethickness-2.xhtml -fails == mfrac-linethickness-3.xhtml mfrac-linethickness-3.xhtml +== mfrac-linethickness-1.xhtml mfrac-linethickness-1.xhtml +== mfrac-linethickness-2.xhtml mfrac-linethickness-2.xhtml +== mfrac-linethickness-3.xhtml mfrac-linethickness-3.xhtml == mathml-negativespace.html mathml-negativespace.html == negative-mspace-1.html negative-mspace-1.html == link-1.xhtml link-1.xhtml -fails == munderover-empty-scripts.html munderover-empty-scripts.html +== munderover-empty-scripts.html munderover-empty-scripts.html == positive-namedspace.html positive-namedspace.html fails == mtable-align-whitespace.html mtable-align-whitespace.html == mtable-width.html mtable-width.html @@ -183,17 +183,17 @@ fails == mtable-columnalign-multi-mtr.html mtable-columnalign-multi-mtr.html fails == mtable-columnalign-multi-mtr-dynamic.html mtable-columnalign-multi-mtr-dynamic.html fails == mtable-columnalign-multi-mtable.html mtable-columnalign-multi-mtable.html fails == mtable-columnalign-multi-mtable-dynamic.html mtable-columnalign-multi-mtable-dynamic.html -fails == maction-selection.html maction-selection.html +== maction-selection.html maction-selection.html == maction-dynamic-embellished-op.html maction-dynamic-embellished-op.html == maction-dynamic-1.html maction-dynamic-1.html == maction-dynamic-2.html maction-dynamic-2.html == mo-lspace-rspace.html mo-lspace-rspace.html fails == mo-lspace-rspace-2.html mo-lspace-rspace-2.html == mo-lspace-rspace-3.html mo-lspace-rspace-3.html -fails == mo-lspace-rspace-4.html mo-lspace-rspace-4.html +== mo-lspace-rspace-4.html mo-lspace-rspace-4.html == mo-invisibleoperators.html mo-invisibleoperators.html == mo-invisibleoperators-2.html mo-invisibleoperators-2.html -fails == mo-glyph-size.html mo-glyph-size.html +== mo-glyph-size.html mo-glyph-size.html == maction-dynamic-3.html maction-dynamic-3.html == whitespace-trim-1.html whitespace-trim-1.html == whitespace-trim-2.html whitespace-trim-2.html @@ -203,9 +203,9 @@ fails == mo-glyph-size.html mo-glyph-size.html == opentype-stretchy.html opentype-stretchy.html == opentype-fraction-dynamic-linethickness.html opentype-fraction-dynamic-linethickness.html == operator-1.xhtml operator-1.xhtml -fails == scriptshift-1.xhtml scriptshift-1.xhtml +== scriptshift-1.xhtml scriptshift-1.xhtml == number-size-1.xhtml number-size-1.xhtml -fails == multiscripts-1.html multiscripts-1.html +== multiscripts-1.html multiscripts-1.html == mathml-mmultiscript-base.html mathml-mmultiscript-base.html == mathml-mmultiscript-mprescript.html mathml-mmultiscript-mprescript.html == menclose-1a.html menclose-1a.html @@ -302,10 +302,10 @@ fails == ssty-3.html ssty-3.html fails == ssty-4.html ssty-4.html fails == mathscript-1.html mathscript-1.html fails == mathscript-2.html mathscript-2.html -fails == mo-accent-dynamic.html mo-accent-dynamic.html -fails == mo-movablelimits-dynamic.html mo-movablelimits-dynamic.html -fails == munderover-accent-dynamic.html munderover-accent-dynamic.html -fails == munderover-accentunder-dynamic.html munderover-accentunder-dynamic.html +== mo-accent-dynamic.html mo-accent-dynamic.html +== mo-movablelimits-dynamic.html mo-movablelimits-dynamic.html +== munderover-accent-dynamic.html munderover-accent-dynamic.html +== munderover-accentunder-dynamic.html munderover-accentunder-dynamic.html fails == columnlines-1a.html columnlines-1a.html fails == columnlines-1b.html columnlines-1b.html fails == columnlines-1c.html columnlines-1c.html @@ -333,41 +333,41 @@ fails == tablespacing-7.html tablespacing-7.html == op-dict-1.html op-dict-1.html == op-dict-2.html op-dict-2.html == op-dict-3.html op-dict-3.html -fails == op-dict-4.html op-dict-4.html -fails == op-dict-5.html op-dict-5.html +== op-dict-4.html op-dict-4.html +== op-dict-5.html op-dict-5.html == op-dict-6.html op-dict-6.html == op-dict-7.html op-dict-7.html == op-dict-8.html op-dict-8.html == op-dict-9.html op-dict-9.html -fails == op-dict-10.html op-dict-10.html +== op-dict-10.html op-dict-10.html fails == op-dict-11.html op-dict-11.html -fails == op-dict-12.html op-dict-12.html -fails == op-dict-13.html op-dict-13.html -fails == mfrac-A-1.html mfrac-A-1.html +== op-dict-12.html op-dict-12.html +== op-dict-13.html op-dict-13.html +== mfrac-A-1.html mfrac-A-1.html == mfrac-A-2.html mfrac-A-2.html == mfrac-A-3.html mfrac-A-3.html == mfrac-A-4.html mfrac-A-4.html -fails == mfrac-A-5.html mfrac-A-5.html +== mfrac-A-5.html mfrac-A-5.html == mfrac-A-6.html mfrac-A-6.html == mfrac-A-7.html mfrac-A-7.html == mfrac-A-8.html mfrac-A-8.html == mfrac-B-1.html mfrac-B-1.html -fails == mfrac-B-2.html mfrac-B-2.html -fails == mfrac-B-3.html mfrac-B-3.html +== mfrac-B-2.html mfrac-B-2.html +== mfrac-B-3.html mfrac-B-3.html fails == mfrac-B-4.html mfrac-B-4.html fails == mfrac-B-5.html mfrac-B-5.html fails == mfrac-B-6.html mfrac-B-6.html fails == mfrac-B-7.html mfrac-B-7.html -fails == mfrac-C-1.html mfrac-C-1.html -fails == mfrac-C-2.html mfrac-C-2.html +== mfrac-C-1.html mfrac-C-1.html +== mfrac-C-2.html mfrac-C-2.html fails == mfrac-C-3.html mfrac-C-3.html fails == mfrac-C-4.html mfrac-C-4.html -fails == mfrac-D-1.html mfrac-D-1.html -fails == mfrac-D-2.html mfrac-D-2.html +== mfrac-D-1.html mfrac-D-1.html +== mfrac-D-2.html mfrac-D-2.html fails == mfrac-D-3.html mfrac-D-3.html fails == mfrac-D-4.html mfrac-D-4.html -fails == mfrac-E-1.html mfrac-E-1.html -fails pref(dom.webcomponents.enabled,true) == shadow-dom-1.html shadow-dom-1.html +== mfrac-E-1.html mfrac-E-1.html +pref(dom.webcomponents.enabled,true) == shadow-dom-1.html shadow-dom-1.html pref(font.size.inflation.emPerLine,25) == font-inflation-1.html font-inflation-1.html fails pref(font.minimum-size.x-math,40) == default-font.html default-font.html == radicalbar-1.html radicalbar-1.html From b81ad83874af1a0c1ffd6206bbdea2e99f10f1af Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 20 Apr 2017 00:20:41 -0500 Subject: [PATCH 18/65] servo: Merge #16539 - stylo: Properly support -moz-script-size-multiplier, -moz-script-level, and -moz-script-min-size (from Manishearth:stylo-scriptminsize); r=heycam r=heycam https://bugzilla.mozilla.org/show_bug.cgi?id=1355427 (copying over the relevant commit message so that it doesn't get lost in the vcssync) scriptlevel is a property that affects how font-size is inherited. If scriptlevel is +1, for example, it will inherit as the script size multiplier times the parent font. This does not affect cases where the font-size is explicitly set. However, this transformation is not allowed to reduce the size below scriptminsize. If this inheritance will reduce it to below scriptminsize, it will be set to scriptminsize or the parent size, whichever is smaller (the parent size could be smaller than the min size because it was explicitly specified). Now, within a node that has inherited a font-size which was crossing scriptminsize once the scriptlevel was applied, a negative scriptlevel may be used to increase the size again. This should work, however if we have already been capped by the scriptminsize multiple times, this can lead to a jump in the size. For example, if we have text of the form: huge large medium small tiny reallytiny tiny small medium huge which is represented by progressive nesting and scriptlevel values of +1 till the center after which the scriptlevel is -1, the "tiny"s should be the same size, as should be the "small"s and "medium"s, etc. However, if scriptminsize kicked it at around "medium", then medium/tiny/reallytiny will all be the same size (the min size). A -1 scriptlevel change after this will increase the min size by the multiplier, making the second tiny larger than medium. Instead, we wish for the second "tiny" to still be capped by the script level, and when we reach the second "large", it should be the same size as the original one. We do this by cascading two separate font sizes. The font size (mSize) is the actual displayed font size. The unconstrained font size (mScriptUnconstrainedSize) is the font size in the situation where scriptminsize never applied. We calculate the proposed inherited font size based on scriptlevel and the parent unconstrained size, instead of using the parent font size. This is stored in the node's unconstrained size and will also be stored in the font size provided that it is above the min size. All of this only applies when inheriting. When the font size is manually set, scriptminsize does not apply, and both the real and unconstrained size are set to the explicit value. However, if the font size is manually set to an em or percent unit, the unconstrained size will be set to the value of that unit computed against the parent unconstrained size, whereas the font size will be set computing against the parent font size. Source-Repo: https://github.com/servo/servo Source-Revision: 7919e591a46274c0d7f3a7c7c99d2643d55d60f1 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : f3222c625f72aa2f70192b0efe8d50d28d7002b2 --- .../components/style/properties/gecko.mako.rs | 165 +++++++++++++++++- .../style/properties/helpers.mako.rs | 52 ++---- .../style/properties/longhand/font.mako.rs | 134 ++++++++++---- .../style/properties/properties.mako.rs | 29 ++- .../style/values/computed/length.rs | 6 +- .../style/values/specified/length.rs | 33 +++- 6 files changed, 332 insertions(+), 87 deletions(-) diff --git a/servo/components/style/properties/gecko.mako.rs b/servo/components/style/properties/gecko.mako.rs index 6197306879b5..87f5ad0d4187 100644 --- a/servo/components/style/properties/gecko.mako.rs +++ b/servo/components/style/properties/gecko.mako.rs @@ -1352,11 +1352,170 @@ fn static_assert() { pub fn set_font_size(&mut self, v: longhands::font_size::computed_value::T) { self.gecko.mFont.size = v.0; self.gecko.mSize = v.0; + self.gecko.mScriptUnconstrainedSize = v.0; } - pub fn copy_font_size_from(&mut self, other: &Self) { - self.gecko.mFont.size = other.gecko.mFont.size; - self.gecko.mSize = other.gecko.mSize; + + /// Set font size, taking into account scriptminsize and scriptlevel + /// Returns Some(size) if we have to recompute the script unconstrained size + pub fn apply_font_size(&mut self, v: longhands::font_size::computed_value::T, + parent: &Self) -> Option { + let (adjusted_size, adjusted_unconstrained_size) + = self.calculate_script_level_size(parent); + // In this case, we have been unaffected by scriptminsize, ignore it + if parent.gecko.mSize == parent.gecko.mScriptUnconstrainedSize && + adjusted_size == adjusted_unconstrained_size { + self.set_font_size(v); + None + } else { + self.gecko.mFont.size = v.0; + self.gecko.mSize = v.0; + Some(Au(parent.gecko.mScriptUnconstrainedSize)) + } } + + pub fn apply_unconstrained_font_size(&mut self, v: Au) { + self.gecko.mScriptUnconstrainedSize = v.0; + } + + /// Calculates the constrained and unconstrained font sizes to be inherited + /// from the parent. + /// + /// See ComputeScriptLevelSize in Gecko's nsRuleNode.cpp + /// + /// scriptlevel is a property that affects how font-size is inherited. If scriptlevel is + /// +1, for example, it will inherit as the script size multiplier times + /// the parent font. This does not affect cases where the font-size is + /// explicitly set. + /// + /// However, this transformation is not allowed to reduce the size below + /// scriptminsize. If this inheritance will reduce it to below + /// scriptminsize, it will be set to scriptminsize or the parent size, + /// whichever is smaller (the parent size could be smaller than the min size + /// because it was explicitly specified). + /// + /// Now, within a node that has inherited a font-size which was + /// crossing scriptminsize once the scriptlevel was applied, a negative + /// scriptlevel may be used to increase the size again. + /// + /// This should work, however if we have already been capped by the + /// scriptminsize multiple times, this can lead to a jump in the size. + /// + /// For example, if we have text of the form: + /// + /// huge large medium small tiny reallytiny tiny small medium huge + /// + /// which is represented by progressive nesting and scriptlevel values of + /// +1 till the center after which the scriptlevel is -1, the "tiny"s should + /// be the same size, as should be the "small"s and "medium"s, etc. + /// + /// However, if scriptminsize kicked it at around "medium", then + /// medium/tiny/reallytiny will all be the same size (the min size). + /// A -1 scriptlevel change after this will increase the min size by the + /// multiplier, making the second tiny larger than medium. + /// + /// Instead, we wish for the second "tiny" to still be capped by the script + /// level, and when we reach the second "large", it should be the same size + /// as the original one. + /// + /// We do this by cascading two separate font sizes. The font size (mSize) + /// is the actual displayed font size. The unconstrained font size + /// (mScriptUnconstrainedSize) is the font size in the situation where + /// scriptminsize never applied. + /// + /// We calculate the proposed inherited font size based on scriptlevel and + /// the parent unconstrained size, instead of using the parent font size. + /// This is stored in the node's unconstrained size and will also be stored + /// in the font size provided that it is above the min size. + /// + /// All of this only applies when inheriting. When the font size is + /// manually set, scriptminsize does not apply, and both the real and + /// unconstrained size are set to the explicit value. However, if the font + /// size is manually set to an em or percent unit, the unconstrained size + /// will be set to the value of that unit computed against the parent + /// unconstrained size, whereas the font size will be set computing against + /// the parent font size. + pub fn calculate_script_level_size(&self, parent: &Self) -> (Au, Au) { + use std::cmp; + + let delta = self.gecko.mScriptLevel - parent.gecko.mScriptLevel; + + let parent_size = Au(parent.gecko.mSize); + let parent_unconstrained_size = Au(parent.gecko.mScriptUnconstrainedSize); + + if delta == 0 { + return (parent_size, parent_unconstrained_size) + } + + /// XXXManishearth this should also handle text zoom + let min = Au(parent.gecko.mScriptMinSize); + + let scale = (parent.gecko.mScriptSizeMultiplier as f32).powi(delta as i32); + + let new_size = parent_size.scale_by(scale); + let new_unconstrained_size = parent_unconstrained_size.scale_by(scale); + + if scale < 1. { + // The parent size can be smaller than scriptminsize, + // e.g. if it was specified explicitly. Don't scale + // in this case, but we don't want to set it to scriptminsize + // either since that will make it larger. + if parent_size < min { + (parent_size, new_unconstrained_size) + } else { + (cmp::max(min, new_size), new_unconstrained_size) + } + } else { + // If the new unconstrained size is larger than the min size, + // this means we have escaped the grasp of scriptminsize + // and can revert to using the unconstrained size. + // However, if the new size is even larger (perhaps due to usage + // of em units), use that instead. + (cmp::min(new_size, cmp::max(new_unconstrained_size, min)), + new_unconstrained_size) + } + } + + /// This function will also handle scriptminsize and scriptlevel + /// so should not be called when you just want the font sizes to be copied. + /// Hence the different name. + pub fn inherit_font_size_from(&mut self, parent: &Self, + kw_inherited_size: Option) { + let (adjusted_size, adjusted_unconstrained_size) + = self.calculate_script_level_size(parent); + if adjusted_size.0 != parent.gecko.mSize || + adjusted_unconstrained_size.0 != parent.gecko.mScriptUnconstrainedSize { + // This is incorrect. When there is both a keyword size being inherited + // and a scriptlevel change, we must handle the keyword size the same + // way we handle em units. This complicates things because we now have + // to keep track of the adjusted and unadjusted ratios in the kw font size. + // This only affects the use case of a generic font being used in MathML. + // + // If we were to fix this I would prefer doing it by removing the + // ruletree walk on the Gecko side in nsRuleNode::SetGenericFont + // and instead using extra bookkeeping in the mSize and mScriptUnconstrainedSize + // values, and reusing those instead of font_size_keyword. + + + // In the case that MathML has given us an adjusted size, apply it. + // Keep track of the unconstrained adjusted size. + self.gecko.mFont.size = adjusted_size.0; + self.gecko.mSize = adjusted_size.0; + self.gecko.mScriptUnconstrainedSize = adjusted_unconstrained_size.0; + } else if let Some(size) = kw_inherited_size { + // Parent element was a keyword-derived size. + self.gecko.mFont.size = size.0; + self.gecko.mSize = size.0; + // MathML constraints didn't apply here, so we can ignore this. + self.gecko.mScriptUnconstrainedSize = size.0; + } else { + // MathML isn't affecting us, and our parent element does not + // have a keyword-derived size. Set things normally. + self.gecko.mFont.size = parent.gecko.mFont.size; + self.gecko.mSize = parent.gecko.mSize; + self.gecko.mScriptUnconstrainedSize = parent.gecko.mScriptUnconstrainedSize; + } + } + pub fn clone_font_size(&self) -> longhands::font_size::computed_value::T { Au(self.gecko.mSize) } diff --git a/servo/components/style/properties/helpers.mako.rs b/servo/components/style/properties/helpers.mako.rs index 49a751bd59f4..a6cb68f160f0 100644 --- a/servo/components/style/properties/helpers.mako.rs +++ b/servo/components/style/properties/helpers.mako.rs @@ -267,31 +267,18 @@ DeclaredValue::Value(ref specified_value) => { let computed = specified_value.to_computed_value(context); % if property.ident == "font_size": - if let longhands::font_size::SpecifiedValue::Keyword(kw, fraction) - = **specified_value { - context.mutate_style().font_size_keyword = Some((kw, fraction)); - } else if let Some(ratio) = specified_value.as_font_ratio() { - // In case a font-size-relative value was applied to a keyword - // value, we must preserve this fact in case the generic font family - // changes. relative values (em and %) applied to keywords must be - // recomputed from the base size for the keyword and the relative size. - // - // See bug 1355707 - if let Some((kw, fraction)) = context.inherited_style().font_size_keyword { - context.mutate_style().font_size_keyword = Some((kw, fraction * ratio)); - } else { - context.mutate_style().font_size_keyword = None; - } - } else { - context.mutate_style().font_size_keyword = None; - } - % endif - % if property.has_uncacheable_values: - context.mutate_style().mutate_${data.current_style_struct.name_lower}() - .set_${property.ident}(computed, cacheable ${maybe_wm}); + longhands::font_size::cascade_specified_font_size(context, + specified_value, + computed, + inherited_style.get_font()); % else: - context.mutate_style().mutate_${data.current_style_struct.name_lower}() - .set_${property.ident}(computed ${maybe_wm}); + % if property.has_uncacheable_values: + context.mutate_style().mutate_${data.current_style_struct.name_lower}() + .set_${property.ident}(computed, cacheable ${maybe_wm}); + % else: + context.mutate_style().mutate_${data.current_style_struct.name_lower}() + .set_${property.ident}(computed ${maybe_wm}); + % endif % endif } DeclaredValue::WithVariables(_) => unreachable!(), @@ -301,13 +288,7 @@ % endif CSSWideKeyword::Initial => { % if property.ident == "font_size": - // font-size's default ("medium") does not always - // compute to the same value and depends on the font - let computed = longhands::font_size::get_initial_specified_value() - .to_computed_value(context); - context.mutate_style().mutate_${data.current_style_struct.name_lower}() - .set_font_size(computed); - context.mutate_style().font_size_keyword = Some((Default::default(), 1.)); + longhands::font_size::cascade_initial_font_size(context); % else: // We assume that it's faster to use copy_*_from rather than // set_*(get_initial_value()); @@ -328,11 +309,12 @@ *cacheable = false; let inherited_struct = inherited_style.get_${data.current_style_struct.name_lower}(); - context.mutate_style().mutate_${data.current_style_struct.name_lower}() - .copy_${property.ident}_from(inherited_struct ${maybe_wm}); + % if property.ident == "font_size": - context.mutate_style().font_size_keyword = - context.inherited_style.font_size_keyword; + longhands::font_size::cascade_inherit_font_size(context, inherited_struct); + % else: + context.mutate_style().mutate_${data.current_style_struct.name_lower}() + .copy_${property.ident}_from(inherited_struct ${maybe_wm}); % endif } } diff --git a/servo/components/style/properties/longhand/font.mako.rs b/servo/components/style/properties/longhand/font.mako.rs index df95d9f464cb..e9ad7208c762 100644 --- a/servo/components/style/properties/longhand/font.mako.rs +++ b/servo/components/style/properties/longhand/font.mako.rs @@ -413,11 +413,13 @@ ${helpers.single_keyword("font-variant-caps", <%helpers:longhand name="font-size" need_clone="True" animation_type="normal" spec="https://drafts.csswg.org/css-fonts/#propdef-font-size"> use app_units::Au; + use properties::style_structs::Font; use std::fmt; use style_traits::ToCss; use values::{FONT_MEDIUM_PX, HasViewportPercentage}; use values::specified::{FontRelativeLength, LengthOrPercentage, Length}; use values::specified::{NoCalcLength, Percentage}; + use values::specified::length::FontBaseSize; impl ToCss for SpecifiedValue { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { @@ -627,6 +629,43 @@ ${helpers.single_keyword("font-variant-caps", } None } + + /// Compute it against a given base font size + pub fn to_computed_value_against(&self, context: &Context, base_size: FontBaseSize) -> Au { + use values::specified::length::FontRelativeLength; + match *self { + SpecifiedValue::Length(LengthOrPercentage::Length( + NoCalcLength::FontRelative(value))) => { + value.to_computed_value(context, base_size) + } + SpecifiedValue::Length(LengthOrPercentage::Length( + NoCalcLength::ServoCharacterWidth(value))) => { + value.to_computed_value(base_size.resolve(context)) + } + SpecifiedValue::Length(LengthOrPercentage::Length(ref l)) => { + l.to_computed_value(context) + } + SpecifiedValue::Length(LengthOrPercentage::Percentage(Percentage(value))) => { + base_size.resolve(context).scale_by(value) + } + SpecifiedValue::Length(LengthOrPercentage::Calc(ref calc)) => { + let calc = calc.to_computed_value(context); + calc.length() + base_size.resolve(context) + .scale_by(calc.percentage()) + } + SpecifiedValue::Keyword(ref key, fraction) => { + key.to_computed_value(context).scale_by(fraction) + } + SpecifiedValue::Smaller => { + FontRelativeLength::Em(0.85) + .to_computed_value(context, base_size) + } + SpecifiedValue::Larger => { + FontRelativeLength::Em(1.2) + .to_computed_value(context, base_size) + } + } + } } #[inline] @@ -640,44 +679,13 @@ ${helpers.single_keyword("font-variant-caps", SpecifiedValue::Keyword(Medium, 1.) } + impl ToComputedValue for SpecifiedValue { type ComputedValue = computed_value::T; #[inline] fn to_computed_value(&self, context: &Context) -> computed_value::T { - use values::specified::length::FontRelativeLength; - match *self { - SpecifiedValue::Length(LengthOrPercentage::Length( - NoCalcLength::FontRelative(value))) => { - value.to_computed_value(context, /* use inherited */ true) - } - SpecifiedValue::Length(LengthOrPercentage::Length( - NoCalcLength::ServoCharacterWidth(value))) => { - value.to_computed_value(context.inherited_style().get_font().clone_font_size()) - } - SpecifiedValue::Length(LengthOrPercentage::Length(ref l)) => { - l.to_computed_value(context) - } - SpecifiedValue::Length(LengthOrPercentage::Percentage(Percentage(value))) => { - context.inherited_style().get_font().clone_font_size().scale_by(value) - } - SpecifiedValue::Length(LengthOrPercentage::Calc(ref calc)) => { - let calc = calc.to_computed_value(context); - calc.length() + context.inherited_style().get_font().clone_font_size() - .scale_by(calc.percentage()) - } - SpecifiedValue::Keyword(ref key, fraction) => { - key.to_computed_value(context).scale_by(fraction) - } - SpecifiedValue::Smaller => { - FontRelativeLength::Em(0.85).to_computed_value(context, - /* use_inherited */ true) - } - SpecifiedValue::Larger => { - FontRelativeLength::Em(1.2).to_computed_value(context, - /* use_inherited */ true) - } - } + self.to_computed_value_against(context, FontBaseSize::InheritedStyle) } #[inline] @@ -703,6 +711,66 @@ ${helpers.single_keyword("font-variant-caps", _ => Err(()) } } + + pub fn cascade_specified_font_size(context: &mut Context, + specified_value: &SpecifiedValue, + computed: Au, + parent: &Font) { + if let SpecifiedValue::Keyword(kw, fraction) + = *specified_value { + context.mutate_style().font_size_keyword = Some((kw, fraction)); + } else if let Some(ratio) = specified_value.as_font_ratio() { + // In case a font-size-relative value was applied to a keyword + // value, we must preserve this fact in case the generic font family + // changes. relative values (em and %) applied to keywords must be + // recomputed from the base size for the keyword and the relative size. + // + // See bug 1355707 + if let Some((kw, fraction)) = context.inherited_style().font_size_keyword { + context.mutate_style().font_size_keyword = Some((kw, fraction * ratio)); + } else { + context.mutate_style().font_size_keyword = None; + } + } else { + context.mutate_style().font_size_keyword = None; + } + + let parent_unconstrained = context.mutate_style() + .mutate_font() + .apply_font_size(computed, + parent); + + if let Some(parent) = parent_unconstrained { + let new_unconstrained = specified_value + .to_computed_value_against(context, FontBaseSize::Custom(parent)); + context.mutate_style() + .mutate_font() + .apply_unconstrained_font_size(new_unconstrained); + } + } + + pub fn cascade_inherit_font_size(context: &mut Context, parent: &Font) { + // If inheriting, we must recompute font-size in case of language changes + // using the font_size_keyword. We also need to do this to handle + // mathml scriptlevel changes + let kw_inherited_size = context.style().font_size_keyword.map(|(kw, ratio)| { + SpecifiedValue::Keyword(kw, ratio).to_computed_value(context) + }); + context.mutate_style().mutate_font() + .inherit_font_size_from(parent, kw_inherited_size); + context.mutate_style().font_size_keyword = + context.inherited_style.font_size_keyword; + } + + pub fn cascade_initial_font_size(context: &mut Context) { + // font-size's default ("medium") does not always + // compute to the same value and depends on the font + let computed = longhands::font_size::get_initial_specified_value() + .to_computed_value(context); + context.mutate_style().mutate_${data.current_style_struct.name_lower}() + .set_font_size(computed); + context.mutate_style().font_size_keyword = Some((Default::default(), 1.)); + } <%helpers:longhand products="gecko" name="font-size-adjust" animation_type="normal" diff --git a/servo/components/style/properties/properties.mako.rs b/servo/components/style/properties/properties.mako.rs index bb5edb137aa3..b53c9254659a 100644 --- a/servo/components/style/properties/properties.mako.rs +++ b/servo/components/style/properties/properties.mako.rs @@ -1429,6 +1429,7 @@ pub use gecko_properties::style_structs; /// The module where all the style structs are defined. #[cfg(feature = "servo")] pub mod style_structs { + use app_units::Au; use fnv::FnvHasher; use super::longhands; use std::hash::{Hash, Hasher}; @@ -1526,6 +1527,23 @@ pub mod style_structs { self.font_family.hash(&mut hasher); self.hash = hasher.finish() } + + /// (Servo does not handle MathML, so this just calls copy_font_size_from) + pub fn inherit_font_size_from(&mut self, parent: &Self, + _: Option) { + self.copy_font_size_from(parent); + } + /// (Servo does not handle MathML, so this just calls set_font_size) + pub fn apply_font_size(&mut self, + v: longhands::font_size::computed_value::T, + _: &Self) -> Option { + self.set_font_size(v); + None + } + /// (Servo does not handle MathML, so this does nothing) + pub fn apply_unconstrained_font_size(&mut self, _: Au) { + } + % elif style_struct.name == "Outline": /// Whether the outline-width property is non-zero. #[inline] @@ -2229,6 +2247,7 @@ pub fn apply_declarations<'a, F, I>(device: &Device, | LonghandId::AnimationName | LonghandId::TransitionProperty | LonghandId::XLang + | LonghandId::MozScriptLevel % endif ); if @@ -2300,12 +2319,12 @@ pub fn apply_declarations<'a, F, I>(device: &Device, &mut cacheable, &mut cascade_info, error_reporter); - } else if let Some((kw, fraction)) = inherited_style.font_size_keyword { - // Font size keywords will inherit as keywords and be recomputed - // each time. + } else { + // Font size must be explicitly inherited to handle keyword + // sizes and scriptlevel let discriminant = LonghandId::FontSize as usize; - let size = PropertyDeclaration::FontSize( - longhands::font_size::SpecifiedValue::Keyword(kw, fraction) + let size = PropertyDeclaration::CSSWideKeyword( + LonghandId::FontSize, CSSWideKeyword::Inherit ); (CASCADE_PROPERTY[discriminant])(&size, inherited_style, diff --git a/servo/components/style/values/computed/length.rs b/servo/components/style/values/computed/length.rs index c21a03c1ca61..be5f70e0807d 100644 --- a/servo/components/style/values/computed/length.rs +++ b/servo/components/style/values/computed/length.rs @@ -10,7 +10,7 @@ use std::fmt; use style_traits::ToCss; use super::{Number, ToComputedValue, Context}; use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified}; -use values::specified::length::{AbsoluteLength, FontRelativeLength, ViewportPercentageLength}; +use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength, ViewportPercentageLength}; pub use super::image::{EndingShape as GradientShape, Gradient, GradientKind, Image}; pub use super::image::{LengthOrKeyword, LengthOrPercentageOrKeyword}; @@ -25,7 +25,7 @@ impl ToComputedValue for specified::NoCalcLength { specified::NoCalcLength::Absolute(length) => length.to_computed_value(context), specified::NoCalcLength::FontRelative(length) => - length.to_computed_value(context, /* use inherited */ false), + length.to_computed_value(context, FontBaseSize::CurrentStyle), specified::NoCalcLength::ViewportPercentage(length) => length.to_computed_value(context.viewport_size()), specified::NoCalcLength::ServoCharacterWidth(length) => @@ -159,7 +159,7 @@ impl ToComputedValue for specified::CalcLengthOrPercentage { self.ex.map(FontRelativeLength::Ex), self.rem.map(FontRelativeLength::Rem)] { if let Some(val) = *val { - length += val.to_computed_value(context, /* use inherited */ false); + length += val.to_computed_value(context, FontBaseSize::CurrentStyle); } } diff --git a/servo/components/style/values/specified/length.rs b/servo/components/style/values/specified/length.rs index 4d41be3e07e4..7897b7815042 100644 --- a/servo/components/style/values/specified/length.rs +++ b/servo/components/style/values/specified/length.rs @@ -76,10 +76,31 @@ impl ToCss for FontRelativeLength { } } +/// A source to resolve font-relative units against +pub enum FontBaseSize { + /// Use the font-size of the current element + CurrentStyle, + /// Use the inherited font-size + InheritedStyle, + /// Use a custom base size + Custom(Au), +} + +impl FontBaseSize { + /// Calculate the actual size for a given context + pub fn resolve(&self, context: &Context) -> Au { + match *self { + FontBaseSize::Custom(size) => size, + FontBaseSize::CurrentStyle => context.style().get_font().clone_font_size(), + FontBaseSize::InheritedStyle => context.inherited_style().get_font().clone_font_size(), + } + } +} + impl FontRelativeLength { - /// Computes the font-relative length. We use the use_inherited flag to - /// special-case the computation of font-size. - pub fn to_computed_value(&self, context: &Context, use_inherited: bool) -> Au { + /// Computes the font-relative length. We use the base_size + /// flag to pass a different size for computing font-size and unconstrained font-size + pub fn to_computed_value(&self, context: &Context, base_size: FontBaseSize) -> Au { fn query_font_metrics(context: &Context, reference_font_size: Au) -> FontMetricsQueryResult { context.font_metrics_provider.query(context.style().get_font(), reference_font_size, @@ -88,11 +109,7 @@ impl FontRelativeLength { context.device) } - let reference_font_size = if use_inherited { - context.inherited_style().get_font().clone_font_size() - } else { - context.style().get_font().clone_font_size() - }; + let reference_font_size = base_size.resolve(context); let root_font_size = context.style().root_font_size; match *self { From e6c145b52b4354ce5551008f6cc311bcaa8430de Mon Sep 17 00:00:00 2001 From: KuoE0 Date: Wed, 19 Apr 2017 11:09:35 +0800 Subject: [PATCH 19/65] Bug 1355005 - Remove the failures mark of `box-orient` in stylo-failures.md. r=heycam MozReview-Commit-ID: GufNFWDyiIq --HG-- extra : rebase_source : e81bb6a316c52c9f7bccc1523d0b88c9b4b0f02b --- layout/style/test/stylo-failures.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/layout/style/test/stylo-failures.md b/layout/style/test/stylo-failures.md index b4d56b011b5d..0f9f0779f37f 100644 --- a/layout/style/test/stylo-failures.md +++ b/layout/style/test/stylo-failures.md @@ -227,8 +227,6 @@ to mochitest command. * SVG-in-OpenType values not supported servo/servo#15211 bug 1355412 * test_value_storage.html `context-` [7] * test_bug798843_pref.html [7] - * -moz-box-orient: {block,inline}-axis bug 1355005 - * test_value_storage.html `box-orient` [6] * Incorrect parsing * Incorrect bounds * test_bug664955.html `font size is larger than max font size` [2] From 166138d46932faf577bd7a84475e84b0c0558178 Mon Sep 17 00:00:00 2001 From: cu1t Date: Thu, 20 Apr 2017 01:01:05 -0500 Subject: [PATCH 20/65] servo: Merge #16472 - Fix namespaces of elements created in XML documents (from cu1t:#14095-fix-xml-doc-namespaces); r=nox MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correctly implement following step of [Dom Document Spec](https://dom.spec.whatwg.org/#dom-document-createelement): > Let namespace be the HTML namespace, if the context object is an HTML document or context object’s content type is "application/xhtml+xml", and null otherwise. Note, this will make following test in `tests/wpt/web-platform-tests/dom/nodes/Document-constructor.html` to fail, so related .ini file added to mark it as such: ``` test(function() { var doc = new Document(); var a = doc.createElement("a"); // In UTF-8: 0xC3 0xA4 a.href = "http://example.org/?\u00E4"; assert_equals(a.href, "http://example.org/?%C3%A4"); }, "new Document(): URL parsing") ``` I'm not very familiar with specs, but from quick look at it, I'm doubtfull that it is valid in the first place. This is an "application/xml" document, so I don't see why it should encode a.href. Firefox also fails that. --- - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #14095 (github issue number if applicable). - [ ] There are tests for these changes OR - [X] These changes do not require tests because because there are already tests which were being ignored Source-Repo: https://github.com/servo/servo Source-Revision: 2d732d829b3fc93938898118ee55ef985ebfc657 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 7fbf8e42f1b8d08344dceb34a890ccf3fdce34df --- servo/components/script/dom/document.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/servo/components/script/dom/document.rs b/servo/components/script/dom/document.rs index 940baaca36f9..425336fd669c 100644 --- a/servo/components/script/dom/document.rs +++ b/servo/components/script/dom/document.rs @@ -2772,7 +2772,14 @@ impl DocumentMethods for Document { if self.is_html_document { local_name.make_ascii_lowercase(); } - let name = QualName::new(ns!(html), LocalName::from(local_name)); + + let ns = if self.is_html_document || self.content_type == "application/xhtml+xml" { + ns!(html) + } else { + ns!() + }; + + let name = QualName::new(ns, LocalName::from(local_name)); Ok(Element::create(name, None, self, ElementCreator::ScriptCreated)) } From 0a4d506e21129d9f2cd5c9fe00649fb947177b4f Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Thu, 20 Apr 2017 10:15:06 +0800 Subject: [PATCH 21/65] Bug 1354349 - Add nsIChannel.isDocument that checks if LOAD_DOCUMENT_URI is set, or if LOAD_HTML_OBJECT_DATA and the channel has the appropriate MIME type r=mcmanus,mystor MozReview-Commit-ID: K28Opd9JTr2 --HG-- extra : rebase_source : d1a786d9b4318be15f195fdc330489121ebd6ece --- dom/ipc/TabParent.cpp | 1 + dom/jsurl/nsJSProtocolHandler.cpp | 6 +++ image/decoders/icon/mac/nsIconChannel.h | 1 + image/decoders/icon/mac/nsIconChannelCocoa.mm | 7 ++++ image/decoders/icon/win/nsIconChannel.cpp | 7 ++++ modules/libjar/nsJARChannel.cpp | 6 +++ netwerk/base/nsBaseChannel.cpp | 6 +++ netwerk/base/nsIChannel.idl | 22 ++++++++++ netwerk/base/nsNetUtil.cpp | 40 +++++++++++++++++++ netwerk/base/nsNetUtil.h | 2 + netwerk/protocol/about/nsAboutCache.h | 1 + netwerk/protocol/http/HttpBaseChannel.cpp | 6 +++ netwerk/protocol/http/HttpBaseChannel.h | 1 + netwerk/protocol/http/NullHttpChannel.cpp | 6 +++ netwerk/protocol/http/nsIHttpChannel.idl | 2 +- .../viewsource/nsViewSourceChannel.cpp | 8 ++++ .../protocol/wyciwyg/WyciwygChannelChild.cpp | 6 +++ netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp | 6 +++ .../converters/nsMultiMixedConv.cpp | 6 +++ .../exthandler/ExternalHelperAppParent.cpp | 6 +++ .../exthandler/nsExternalProtocolHandler.cpp | 5 +++ 21 files changed, 150 insertions(+), 1 deletion(-) diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index b2bd8f152d1d..168ee5561912 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -2956,6 +2956,7 @@ public: NS_IMETHOD SetLoadGroup(nsILoadGroup*) NO_IMPL NS_IMETHOD SetLoadFlags(nsLoadFlags) NO_IMPL NS_IMETHOD GetLoadFlags(nsLoadFlags*) NO_IMPL + NS_IMETHOD GetIsDocument(bool *) NO_IMPL NS_IMETHOD GetOriginalURI(nsIURI**) NO_IMPL NS_IMETHOD SetOriginalURI(nsIURI*) NO_IMPL NS_IMETHOD GetURI(nsIURI** aUri) override diff --git a/dom/jsurl/nsJSProtocolHandler.cpp b/dom/jsurl/nsJSProtocolHandler.cpp index 0c1b5d9599fc..1e53e93e2775 100644 --- a/dom/jsurl/nsJSProtocolHandler.cpp +++ b/dom/jsurl/nsJSProtocolHandler.cpp @@ -442,6 +442,12 @@ nsresult nsJSChannel::Init(nsIURI* aURI, nsILoadInfo* aLoadInfo) return rv; } +NS_IMETHODIMP +nsJSChannel::GetIsDocument(bool *aIsDocument) +{ + return NS_GetIsDocumentChannel(this, aIsDocument); +} + // // nsISupports implementation... // diff --git a/image/decoders/icon/mac/nsIconChannel.h b/image/decoders/icon/mac/nsIconChannel.h index 9fef171193e9..208f556d2e72 100644 --- a/image/decoders/icon/mac/nsIconChannel.h +++ b/image/decoders/icon/mac/nsIconChannel.h @@ -19,6 +19,7 @@ #include "nsIInputStreamPump.h" #include "nsIStreamListener.h" #include "nsIURI.h" +#include "nsNetUtil.h" class nsIFile; diff --git a/image/decoders/icon/mac/nsIconChannelCocoa.mm b/image/decoders/icon/mac/nsIconChannelCocoa.mm index b90e166d1801..2bb05e333e29 100644 --- a/image/decoders/icon/mac/nsIconChannelCocoa.mm +++ b/image/decoders/icon/mac/nsIconChannelCocoa.mm @@ -27,6 +27,7 @@ #include "nsObjCExceptions.h" #include "nsProxyRelease.h" #include "nsContentSecurityManager.h" +#include "nsNetUtil.h" #include @@ -429,6 +430,12 @@ nsIconChannel::SetLoadFlags(uint32_t aLoadAttributes) return mPump->SetLoadFlags(aLoadAttributes); } +NS_IMETHODIMP +nsIconChannel::GetIsDocument(bool *aIsDocument) +{ + return NS_GetIsDocumentChannel(this, aIsDocument); +} + NS_IMETHODIMP nsIconChannel::GetContentType(nsACString& aContentType) { diff --git a/image/decoders/icon/win/nsIconChannel.cpp b/image/decoders/icon/win/nsIconChannel.cpp index 4ae8932691b9..42c42d8c0f4b 100644 --- a/image/decoders/icon/win/nsIconChannel.cpp +++ b/image/decoders/icon/win/nsIconChannel.cpp @@ -28,6 +28,7 @@ #include "nsProxyRelease.h" #include "nsContentSecurityManager.h" #include "nsContentUtils.h" +#include "nsNetUtil.h" // we need windows.h to read out registry information... #include @@ -157,6 +158,12 @@ nsIconChannel::SetLoadFlags(uint32_t aLoadAttributes) return mPump->SetLoadFlags(aLoadAttributes); } +NS_IMETHODIMP +nsIconChannel::GetIsDocument(bool *aIsDocument) +{ + return NS_GetIsDocumentChannel(this, aIsDocument); +} + //////////////////////////////////////////////////////////////////////////////// // nsIChannel methods: diff --git a/modules/libjar/nsJARChannel.cpp b/modules/libjar/nsJARChannel.cpp index 7e69cb341046..85383dc16cf9 100644 --- a/modules/libjar/nsJARChannel.cpp +++ b/modules/libjar/nsJARChannel.cpp @@ -486,6 +486,12 @@ nsJARChannel::SetLoadFlags(nsLoadFlags aLoadFlags) return NS_OK; } +NS_IMETHODIMP +nsJARChannel::GetIsDocument(bool *aIsDocument) +{ + return NS_GetIsDocumentChannel(this, aIsDocument); +} + NS_IMETHODIMP nsJARChannel::GetLoadGroup(nsILoadGroup **aLoadGroup) { diff --git a/netwerk/base/nsBaseChannel.cpp b/netwerk/base/nsBaseChannel.cpp index 42173b49d14b..f45a1e3b6848 100644 --- a/netwerk/base/nsBaseChannel.cpp +++ b/netwerk/base/nsBaseChannel.cpp @@ -503,6 +503,12 @@ nsBaseChannel::GetLoadInfo(nsILoadInfo** aLoadInfo) return NS_OK; } +NS_IMETHODIMP +nsBaseChannel::GetIsDocument(bool *aIsDocument) +{ + return NS_GetIsDocumentChannel(this, aIsDocument); +} + NS_IMETHODIMP nsBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks) { diff --git a/netwerk/base/nsIChannel.idl b/netwerk/base/nsIChannel.idl index 743e942920d2..2be8e88c3736 100644 --- a/netwerk/base/nsIChannel.idl +++ b/netwerk/base/nsIChannel.idl @@ -208,6 +208,9 @@ interface nsIChannel : nsIRequest /** * Set (e.g., by the docshell) to indicate whether or not the channel * corresponds to a document URI. + * While setting this flag is sufficient to mark a channel as a document + * load, _checking_ whether the channel is a document load requires the use + * of the new channel.isDocument */ const unsigned long LOAD_DOCUMENT_URI = 1 << 16; @@ -344,7 +347,26 @@ interface nsIChannel : nsIRequest */ attribute nsILoadInfo loadInfo; + /** + * Returns true if the channel is used to create a document. + * It returns true if the loadFlags have LOAD_DOCUMENT_URI set, or if + * LOAD_HTML_OBJECT_DATA is set and the channel has the appropriate + * MIME type. + * Note: May have the wrong value if called before OnStartRequest as we + * don't know the MIME type yet. + */ + readonly attribute bool isDocument; + %{ C++ + inline bool IsDocument() + { + bool isDocument = false; + if (NS_SUCCEEDED(GetIsDocument(&isDocument)) && isDocument) { + return true; + } + return false; + } + inline already_AddRefed GetLoadInfo() { nsCOMPtr result; diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp index 2f897f38dba3..e8a24f60ca80 100644 --- a/netwerk/base/nsNetUtil.cpp +++ b/netwerk/base/nsNetUtil.cpp @@ -36,6 +36,7 @@ #include "nsIMIMEHeaderParam.h" #include "nsIMutable.h" #include "nsINode.h" +#include "nsIObjectLoadingContent.h" #include "nsIOfflineCacheUpdate.h" #include "nsIPersistentProperties2.h" #include "nsIPrivateBrowsingChannel.h" @@ -357,6 +358,45 @@ NS_NewChannel(nsIChannel **outChannel, aIoService); } +nsresult +NS_GetIsDocumentChannel(nsIChannel * aChannel, bool *aIsDocument) +{ + // Check if this channel is going to be used to create a document. If it has + // LOAD_DOCUMENT_URI set it is trivially creating a document. If + // LOAD_HTML_OBJECT_DATA is set it may or may not be used to create a + // document, depending on its MIME type. + + *aIsDocument = false; + if (!aChannel || !aIsDocument) { + return NS_ERROR_NULL_POINTER; + } + nsLoadFlags loadFlags; + nsresult rv = aChannel->GetLoadFlags(&loadFlags); + if (NS_FAILED(rv)) { + return rv; + } + if (loadFlags & nsIChannel::LOAD_DOCUMENT_URI) { + *aIsDocument = true; + return NS_OK; + } + if (!(loadFlags & nsIRequest::LOAD_HTML_OBJECT_DATA)) { + *aIsDocument = false; + return NS_OK; + } + nsAutoCString mimeType; + rv = aChannel->GetContentType(mimeType); + if (NS_FAILED(rv)) { + return rv; + } + if (nsContentUtils::HtmlObjectContentTypeForMIMEType(mimeType, nullptr) == + nsIObjectLoadingContent::TYPE_DOCUMENT) { + *aIsDocument = true; + return NS_OK; + } + *aIsDocument = false; + return NS_OK; +} + nsresult NS_MakeAbsoluteURI(nsACString &result, const nsACString &spec, diff --git a/netwerk/base/nsNetUtil.h b/netwerk/base/nsNetUtil.h index d094bf9b7e30..2a1974282fea 100644 --- a/netwerk/base/nsNetUtil.h +++ b/netwerk/base/nsNetUtil.h @@ -190,6 +190,8 @@ NS_NewChannel(nsIChannel **outChannel, nsLoadFlags aLoadFlags = nsIRequest::LOAD_NORMAL, nsIIOService *aIoService = nullptr); +nsresult NS_GetIsDocumentChannel(nsIChannel * aChannel, bool *aIsDocument); + nsresult NS_MakeAbsoluteURI(nsACString &result, const nsACString &spec, nsIURI *baseURI); diff --git a/netwerk/protocol/about/nsAboutCache.h b/netwerk/protocol/about/nsAboutCache.h index c2d1af85054b..488d2c8ea820 100644 --- a/netwerk/protocol/about/nsAboutCache.h +++ b/netwerk/protocol/about/nsAboutCache.h @@ -39,6 +39,7 @@ NS_IMETHOD GetContentDispositionHeader(nsACString & aContentDispositionHeader) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetContentDispositionHeader(aContentDispositionHeader); } \ NS_IMETHOD GetLoadInfo(nsILoadInfo * *aLoadInfo) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetLoadInfo(aLoadInfo); } \ NS_IMETHOD SetLoadInfo(nsILoadInfo *aLoadInfo) override { return !_to ? NS_ERROR_NULL_POINTER : _to->SetLoadInfo(aLoadInfo); } \ + NS_IMETHOD GetIsDocument(bool *aIsDocument) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetIsDocument(aIsDocument); }; \ class nsAboutCache final : public nsIAboutModule { diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index a5e53dd2ba47..0742df96a633 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -535,6 +535,12 @@ HttpBaseChannel::GetLoadInfo(nsILoadInfo **aLoadInfo) return NS_OK; } +NS_IMETHODIMP +HttpBaseChannel::GetIsDocument(bool *aIsDocument) +{ + return NS_GetIsDocumentChannel(this, aIsDocument); +} + NS_IMETHODIMP HttpBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks) { diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index 591c08496ea8..f11aa43ed9b9 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -135,6 +135,7 @@ public: NS_IMETHOD SetOwner(nsISupports *aOwner) override; NS_IMETHOD GetLoadInfo(nsILoadInfo **aLoadInfo) override; NS_IMETHOD SetLoadInfo(nsILoadInfo *aLoadInfo) override; + NS_IMETHOD GetIsDocument(bool *aIsDocument) override; NS_IMETHOD GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks) override; NS_IMETHOD SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks) override; NS_IMETHOD GetContentType(nsACString& aContentType) override; diff --git a/netwerk/protocol/http/NullHttpChannel.cpp b/netwerk/protocol/http/NullHttpChannel.cpp index 12fdb7b29347..59da1a36b2ea 100644 --- a/netwerk/protocol/http/NullHttpChannel.cpp +++ b/netwerk/protocol/http/NullHttpChannel.cpp @@ -539,6 +539,12 @@ NullHttpChannel::SetLoadFlags(nsLoadFlags aLoadFlags) return NS_ERROR_NOT_IMPLEMENTED; } +NS_IMETHODIMP +NullHttpChannel::GetIsDocument(bool *aIsDocument) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + //----------------------------------------------------------------------------- // NullHttpChannel::nsITimedChannel //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/http/nsIHttpChannel.idl b/netwerk/protocol/http/nsIHttpChannel.idl index c3ad1330078f..e9bf4d2f8892 100644 --- a/netwerk/protocol/http/nsIHttpChannel.idl +++ b/netwerk/protocol/http/nsIHttpChannel.idl @@ -286,7 +286,7 @@ interface nsIHttpChannel : nsIChannel /** Indicates whether channel should be treated as the main one for the * current document. If manually set to true, will always remain true. Otherwise, - * will be true iff LOAD_DOCUMENT_URI is set in the channel's loadflags. + * will be true if LOAD_DOCUMENT_URI is set in the channel's loadflags. */ [must_use] attribute boolean isMainDocumentChannel; diff --git a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp index ddf81e2b95dc..2100225fc3c7 100644 --- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp +++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp @@ -573,6 +573,14 @@ nsViewSourceChannel::SetLoadInfo(nsILoadInfo* aLoadInfo) return mChannel->SetLoadInfo(aLoadInfo); } +NS_IMETHODIMP +nsViewSourceChannel::GetIsDocument(bool *aIsDocument) +{ + NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); + + return mChannel->GetIsDocument(aIsDocument); +} + NS_IMETHODIMP nsViewSourceChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks) { diff --git a/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp b/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp index 28ccbdf89c75..32ffaef2c42a 100644 --- a/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp +++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp @@ -493,6 +493,12 @@ WyciwygChannelChild::SetLoadInfo(nsILoadInfo* aLoadInfo) return NS_OK; } +NS_IMETHODIMP +WyciwygChannelChild::GetIsDocument(bool *aIsDocument) +{ + return NS_GetIsDocumentChannel(this, aIsDocument); +} + NS_IMETHODIMP WyciwygChannelChild::GetNotificationCallbacks(nsIInterfaceRequestor * *aCallbacks) { diff --git a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp index bc341a1530c7..d2f20b80a29e 100644 --- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp +++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp @@ -166,6 +166,12 @@ nsWyciwygChannel::GetLoadFlags(uint32_t * aLoadFlags) return NS_OK; } +NS_IMETHODIMP +nsWyciwygChannel::GetIsDocument(bool *aIsDocument) +{ + return NS_GetIsDocumentChannel(this, aIsDocument); +} + //////////////////////////////////////////////////////////////////////////////// // nsIChannel methods: /////////////////////////////////////////////////////////////////////////////// diff --git a/netwerk/streamconv/converters/nsMultiMixedConv.cpp b/netwerk/streamconv/converters/nsMultiMixedConv.cpp index e4e4b5c6f913..d0f62d919e26 100644 --- a/netwerk/streamconv/converters/nsMultiMixedConv.cpp +++ b/netwerk/streamconv/converters/nsMultiMixedConv.cpp @@ -227,6 +227,12 @@ nsPartChannel::SetLoadFlags(nsLoadFlags aLoadFlags) return NS_OK; } +NS_IMETHODIMP +nsPartChannel::GetIsDocument(bool *aIsDocument) +{ + return NS_GetIsDocumentChannel(this, aIsDocument); +} + NS_IMETHODIMP nsPartChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup) { diff --git a/uriloader/exthandler/ExternalHelperAppParent.cpp b/uriloader/exthandler/ExternalHelperAppParent.cpp index 9ca7a6d88fa0..5bd84d70e50b 100644 --- a/uriloader/exthandler/ExternalHelperAppParent.cpp +++ b/uriloader/exthandler/ExternalHelperAppParent.cpp @@ -350,6 +350,12 @@ ExternalHelperAppParent::SetLoadFlags(nsLoadFlags aLoadFlags) return NS_OK; } +NS_IMETHODIMP +ExternalHelperAppParent::GetIsDocument(bool *aIsDocument) +{ + return NS_GetIsDocumentChannel(this, aIsDocument); +} + NS_IMETHODIMP ExternalHelperAppParent::GetLoadGroup(nsILoadGroup* *aLoadGroup) { diff --git a/uriloader/exthandler/nsExternalProtocolHandler.cpp b/uriloader/exthandler/nsExternalProtocolHandler.cpp index 3b264c2c69fd..2ab27c37d90f 100644 --- a/uriloader/exthandler/nsExternalProtocolHandler.cpp +++ b/uriloader/exthandler/nsExternalProtocolHandler.cpp @@ -245,6 +245,11 @@ NS_IMETHODIMP nsExtProtocolChannel::SetLoadFlags(nsLoadFlags aLoadFlags) return NS_OK; } +NS_IMETHODIMP nsExtProtocolChannel::GetIsDocument(bool *aIsDocument) +{ + return NS_GetIsDocumentChannel(this, aIsDocument); +} + NS_IMETHODIMP nsExtProtocolChannel::GetContentType(nsACString &aContentType) { return NS_ERROR_NOT_IMPLEMENTED; From 061dd9b679c9bfce4cc9026104099b0a90b53c39 Mon Sep 17 00:00:00 2001 From: Valentin Gosu Date: Thu, 20 Apr 2017 10:15:16 +0800 Subject: [PATCH 22/65] Bug 1354349 - Use channel.isDocument in ContentParent::TransmitPermissionsFor r=mystor MozReview-Commit-ID: L9b6UeXJ8o5 --HG-- extra : rebase_source : bdcdbd0ee7d7399495cb265d15437a82a654e694 --- dom/ipc/ContentParent.cpp | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 8d746d31416d..fb2d3996f9c1 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -5029,27 +5029,10 @@ ContentParent::TransmitPermissionsFor(nsIChannel* aChannel) { MOZ_ASSERT(aChannel); #ifdef MOZ_PERMISSIONS - // Check if this channel is going to be used to create a document. If it has - // LOAD_DOCUMENT_URI set it is trivially creating a document. If - // LOAD_HTML_OBJECT_DATA is set it may or may not be used to create a - // document, depending on its MIME type. - nsLoadFlags loadFlags; - nsresult rv = aChannel->GetLoadFlags(&loadFlags); - NS_ENSURE_SUCCESS(rv, rv); - if (!(loadFlags & nsIChannel::LOAD_DOCUMENT_URI)) { - if (loadFlags & nsIRequest::LOAD_HTML_OBJECT_DATA) { - nsAutoCString mimeType; - aChannel->GetContentType(mimeType); - if (nsContentUtils::HtmlObjectContentTypeForMIMEType(mimeType, nullptr) != - nsIObjectLoadingContent::TYPE_DOCUMENT) { - // The MIME type would not cause the creation of a document - return NS_OK; - } - } else { - // neither flag was set - return NS_OK; - } + nsresult rv; + if (!aChannel->IsDocument()) { + return NS_OK; } // Get the principal for the channel result, so that we can get the permission From 6419084416e5bbaa76e8cdba81f6267bf78e2806 Mon Sep 17 00:00:00 2001 From: Mark Banner Date: Tue, 18 Apr 2017 20:06:02 +0100 Subject: [PATCH 23/65] Bug 1357502 - Change eslint-plugin-mozilla tests to use the mocha test harness to improve the output. r=mossop MozReview-Commit-ID: 1xI0tBpbSgM --HG-- extra : rebase_source : 227dc315767083e88ec88219771d66fade3072b2 --- .../eslint/eslint-plugin-mozilla/package.json | 5 +- .../avoid-nsISupportsString-preferences.js | 39 ++-- .../tests/avoid-removeChild.js | 39 ++-- .../tests/balanced-listeners.js | 85 +++---- .../tests/no-useless-parameters.js | 211 +++++++++--------- .../tests/no-useless-removeEventListener.js | 111 ++++----- .../test-no-import-into-var-and-global.js | 31 +-- .../tests/test-no-single-arg-cu-import.js | 23 +- .../tests/test-run-all.js | 18 -- .../tests/use-default-preference-values.js | 29 +-- .../tests/use-ownerGlobal.js | 31 +-- 11 files changed, 308 insertions(+), 314 deletions(-) delete mode 100644 tools/lint/eslint/eslint-plugin-mozilla/tests/test-run-all.js diff --git a/tools/lint/eslint/eslint-plugin-mozilla/package.json b/tools/lint/eslint/eslint-plugin-mozilla/package.json index 81e150ff4bad..7f44788744e3 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/package.json +++ b/tools/lint/eslint/eslint-plugin-mozilla/package.json @@ -27,12 +27,15 @@ "ini-parser": "^0.0.2", "sax": "^1.2.2" }, + "devDependencies": { + "mocha": "3.2.0" + }, "engines": { "node": ">=6.9.1" }, "scripts": { "prepublishOnly": "node scripts/createExports.js", - "test": "node tests/test-run-all.js", + "test": "mocha -R dot tests", "postpublish": "rm -f lib/modules.json lib/environments/saved-globals.json" }, "license": "MPL-2.0" diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-nsISupportsString-preferences.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-nsISupportsString-preferences.js index 619b54f9e183..883b8508601c 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-nsISupportsString-preferences.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-nsISupportsString-preferences.js @@ -8,6 +8,9 @@ // ------------------------------------------------------------------------------ var rule = require("../lib/rules/avoid-nsISupportsString-preferences"); +var RuleTester = require("eslint/lib/testers/rule-tester"); + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); // ------------------------------------------------------------------------------ // Tests @@ -19,22 +22,20 @@ function invalidCode(code, accessType = "get") { return {code, errors: [{message, type: "CallExpression"}]}; } -exports.runTest = function(ruleTester) { - ruleTester.run("no-useless-removeEventListener", rule, { - valid: [ - "branch.getStringPref('name');", - "branch.getComplexValue('name', Ci.nsIPrefLocalizedString);", - "branch.setStringPref('name', 'blah');", - "branch.setComplexValue('name', Ci.nsIPrefLocalizedString, pref);" - ], - invalid: [ - invalidCode("branch.getComplexValue('name', Ci.nsISupportsString);"), - invalidCode("branch.getComplexValue('name', nsISupportsString);"), - invalidCode("branch.getComplexValue('name', Ci.nsISupportsString).data;"), - invalidCode("branch.setComplexValue('name', Ci.nsISupportsString, str);", - "set"), - invalidCode("branch.setComplexValue('name', nsISupportsString, str);", - "set") - ] - }); -}; +ruleTester.run("avoid-nsISupportsString-preferences", rule, { + valid: [ + "branch.getStringPref('name');", + "branch.getComplexValue('name', Ci.nsIPrefLocalizedString);", + "branch.setStringPref('name', 'blah');", + "branch.setComplexValue('name', Ci.nsIPrefLocalizedString, pref);" + ], + invalid: [ + invalidCode("branch.getComplexValue('name', Ci.nsISupportsString);"), + invalidCode("branch.getComplexValue('name', nsISupportsString);"), + invalidCode("branch.getComplexValue('name', Ci.nsISupportsString).data;"), + invalidCode("branch.setComplexValue('name', Ci.nsISupportsString, str);", + "set"), + invalidCode("branch.setComplexValue('name', nsISupportsString, str);", + "set") + ] +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-removeChild.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-removeChild.js index af17776bd684..926c34a68b32 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-removeChild.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-removeChild.js @@ -8,6 +8,9 @@ // ------------------------------------------------------------------------------ var rule = require("../lib/rules/avoid-removeChild"); +var RuleTester = require("eslint/lib/testers/rule-tester"); + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); // ------------------------------------------------------------------------------ // Tests @@ -21,22 +24,20 @@ function invalidCode(code, message) { return {code, errors: [{message, type: "CallExpression"}]}; } -exports.runTest = function(ruleTester) { - ruleTester.run("no-useless-removeEventListener", rule, { - valid: [ - "elt.remove();", - "elt.parentNode.parentNode.removeChild(elt2.parentNode);", - "elt.parentNode.removeChild(elt2);", - "elt.removeChild(elt2);" - ], - invalid: [ - invalidCode("elt.parentNode.removeChild(elt);"), - invalidCode("elt.parentNode.parentNode.removeChild(elt.parentNode);"), - invalidCode("$(e).parentNode.removeChild($(e));"), - invalidCode("$('e').parentNode.removeChild($('e'));"), - invalidCode("elt.removeChild(elt.firstChild);", - "use element.firstChild.remove() instead of " + - "element.removeChild(element.firstChild)") - ] - }); -}; +ruleTester.run("avoid-removeChild", rule, { + valid: [ + "elt.remove();", + "elt.parentNode.parentNode.removeChild(elt2.parentNode);", + "elt.parentNode.removeChild(elt2);", + "elt.removeChild(elt2);" + ], + invalid: [ + invalidCode("elt.parentNode.removeChild(elt);"), + invalidCode("elt.parentNode.parentNode.removeChild(elt.parentNode);"), + invalidCode("$(e).parentNode.removeChild($(e));"), + invalidCode("$('e').parentNode.removeChild($('e'));"), + invalidCode("elt.removeChild(elt.firstChild);", + "use element.firstChild.remove() instead of " + + "element.removeChild(element.firstChild)") + ] +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/balanced-listeners.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/balanced-listeners.js index 65c0039a5a86..be810a65030c 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/tests/balanced-listeners.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/balanced-listeners.js @@ -8,6 +8,9 @@ // ------------------------------------------------------------------------------ var rule = require("../lib/rules/balanced-listeners"); +var RuleTester = require("eslint/lib/testers/rule-tester"); + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); // ------------------------------------------------------------------------------ // Tests @@ -20,59 +23,57 @@ function error(code, message) { }; } -exports.runTest = function(ruleTester) { - ruleTester.run("balanced-listeners", rule, { - valid: [ - "elt.addEventListener('event', handler);" + - "elt.removeEventListener('event', handler);", +ruleTester.run("balanced-listeners", rule, { + valid: [ + "elt.addEventListener('event', handler);" + + "elt.removeEventListener('event', handler);", - "elt.addEventListener('event', handler, true);" + - "elt.removeEventListener('event', handler, true);", + "elt.addEventListener('event', handler, true);" + + "elt.removeEventListener('event', handler, true);", - "elt.addEventListener('event', handler, false);" + - "elt.removeEventListener('event', handler, false);", + "elt.addEventListener('event', handler, false);" + + "elt.removeEventListener('event', handler, false);", - "elt.addEventListener('event', handler);" + - "elt.removeEventListener('event', handler, false);", + "elt.addEventListener('event', handler);" + + "elt.removeEventListener('event', handler, false);", - "elt.addEventListener('event', handler, false);" + - "elt.removeEventListener('event', handler);", + "elt.addEventListener('event', handler, false);" + + "elt.removeEventListener('event', handler);", - "elt.addEventListener('event', handler, {capture: false});" + - "elt.removeEventListener('event', handler);", + "elt.addEventListener('event', handler, {capture: false});" + + "elt.removeEventListener('event', handler);", - "elt.addEventListener('event', handler);" + - "elt.removeEventListener('event', handler, {capture: false});", + "elt.addEventListener('event', handler);" + + "elt.removeEventListener('event', handler, {capture: false});", - "elt.addEventListener('event', handler, {capture: true});" + - "elt.removeEventListener('event', handler, true);", + "elt.addEventListener('event', handler, {capture: true});" + + "elt.removeEventListener('event', handler, true);", - "elt.addEventListener('event', handler, true);" + - "elt.removeEventListener('event', handler, {capture: true});", + "elt.addEventListener('event', handler, true);" + + "elt.removeEventListener('event', handler, {capture: true});", - "elt.addEventListener('event', handler, {once: true});", + "elt.addEventListener('event', handler, {once: true});", - "elt.addEventListener('event', handler, {once: true, capture: true});" - ], - invalid: [ - error("elt.addEventListener('click', handler, false);", - "No corresponding 'removeEventListener(click)' was found."), + "elt.addEventListener('event', handler, {once: true, capture: true});" + ], + invalid: [ + error("elt.addEventListener('click', handler, false);", + "No corresponding 'removeEventListener(click)' was found."), - error("elt.addEventListener('click', handler, false);" + - "elt.removeEventListener('click', handler, true);", - "No corresponding 'removeEventListener(click)' was found."), + error("elt.addEventListener('click', handler, false);" + + "elt.removeEventListener('click', handler, true);", + "No corresponding 'removeEventListener(click)' was found."), - error("elt.addEventListener('click', handler, {capture: false});" + - "elt.removeEventListener('click', handler, true);", - "No corresponding 'removeEventListener(click)' was found."), + error("elt.addEventListener('click', handler, {capture: false});" + + "elt.removeEventListener('click', handler, true);", + "No corresponding 'removeEventListener(click)' was found."), - error("elt.addEventListener('click', handler, {capture: true});" + - "elt.removeEventListener('click', handler);", - "No corresponding 'removeEventListener(click)' was found."), + error("elt.addEventListener('click', handler, {capture: true});" + + "elt.removeEventListener('click', handler);", + "No corresponding 'removeEventListener(click)' was found."), - error("elt.addEventListener('click', handler, true);" + - "elt.removeEventListener('click', handler);", - "No corresponding 'removeEventListener(click)' was found.") - ] - }); -}; + error("elt.addEventListener('click', handler, true);" + + "elt.removeEventListener('click', handler);", + "No corresponding 'removeEventListener(click)' was found.") + ] +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-parameters.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-parameters.js index 2b1552826967..5f9a96ead182 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-parameters.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-parameters.js @@ -8,6 +8,9 @@ // ------------------------------------------------------------------------------ var rule = require("../lib/rules/no-useless-parameters"); +var RuleTester = require("eslint/lib/testers/rule-tester"); + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); // ------------------------------------------------------------------------------ // Tests @@ -17,108 +20,106 @@ function callError(message) { return [{message, type: "CallExpression"}]; } -exports.runTest = function(ruleTester) { - ruleTester.run("no-useless-parameters", rule, { - valid: [ - "Services.prefs.clearUserPref('browser.search.custom');", - "Services.removeObserver('notification name', {});", - "Services.io.newURI('http://example.com');", - "Services.io.newURI('http://example.com', 'utf8');", - "elt.addEventListener('click', handler);", - "elt.addEventListener('click', handler, true);", - "elt.addEventListener('click', handler, {once: true});", - "elt.removeEventListener('click', handler);", - "elt.removeEventListener('click', handler, true);", - "Services.obs.addObserver(this, 'topic', true);", - "Services.obs.addObserver(this, 'topic');", - "Services.prefs.addObserver('branch', this, true);", - "Services.prefs.addObserver('branch', this);", - "array.appendElement(elt);", - "Services.obs.notifyObservers(obj, 'topic', 'data');", - "Services.obs.notifyObservers(obj, 'topic');", - "window.getComputedStyle(elt);", - "window.getComputedStyle(elt, ':before');" - ], - invalid: [ - { - code: "Services.prefs.clearUserPref('browser.search.custom', false);", - errors: callError("clearUserPref takes only 1 parameter.") - }, - { - code: "Services.removeObserver('notification name', {}, false);", - errors: callError("removeObserver only takes 2 parameters.") - }, - { - code: "Services.removeObserver('notification name', {}, true);", - errors: callError("removeObserver only takes 2 parameters.") - }, - { - code: "Services.io.newURI('http://example.com', null, null);", - errors: callError("newURI's last parameters are optional.") - }, - { - code: "Services.io.newURI('http://example.com', 'utf8', null);", - errors: callError("newURI's last parameters are optional.") - }, - { - code: "Services.io.newURI('http://example.com', null);", - errors: callError("newURI's last parameters are optional.") - }, - { - code: "Services.io.newURI('http://example.com', '', '');", - errors: callError("newURI's last parameters are optional.") - }, - { - code: "Services.io.newURI('http://example.com', '');", - errors: callError("newURI's last parameters are optional.") - }, - { - code: "elt.addEventListener('click', handler, false);", - errors: callError( - "addEventListener's third parameter can be omitted when it's false.") - }, - { - code: "elt.removeEventListener('click', handler, false);", - errors: callError( - "removeEventListener's third parameter can be omitted when it's" + - " false.") - }, - { - code: "Services.obs.addObserver(this, 'topic', false);", - errors: callError( - "addObserver's third parameter can be omitted when it's" + - " false.") - }, - { - code: "Services.prefs.addObserver('branch', this, false);", - errors: callError( - "addObserver's third parameter can be omitted when it's" + - " false.") - }, - { - code: "array.appendElement(elt, false);", - errors: callError( - "appendElement's second parameter can be omitted when it's" + - " false.") - }, - { - code: "Services.obs.notifyObservers(obj, 'topic', null);", - errors: callError( - "notifyObservers's third parameter can be omitted.") - }, - { - code: "Services.obs.notifyObservers(obj, 'topic', '');", - errors: callError( - "notifyObservers's third parameter can be omitted.") - }, - { - code: "window.getComputedStyle(elt, null);", - errors: callError("getComputedStyle's second parameter can be omitted.") - }, - { - code: "window.getComputedStyle(elt, '');", - errors: callError("getComputedStyle's second parameter can be omitted.") - } - ] - }); -}; +ruleTester.run("no-useless-parameters", rule, { + valid: [ + "Services.prefs.clearUserPref('browser.search.custom');", + "Services.removeObserver('notification name', {});", + "Services.io.newURI('http://example.com');", + "Services.io.newURI('http://example.com', 'utf8');", + "elt.addEventListener('click', handler);", + "elt.addEventListener('click', handler, true);", + "elt.addEventListener('click', handler, {once: true});", + "elt.removeEventListener('click', handler);", + "elt.removeEventListener('click', handler, true);", + "Services.obs.addObserver(this, 'topic', true);", + "Services.obs.addObserver(this, 'topic');", + "Services.prefs.addObserver('branch', this, true);", + "Services.prefs.addObserver('branch', this);", + "array.appendElement(elt);", + "Services.obs.notifyObservers(obj, 'topic', 'data');", + "Services.obs.notifyObservers(obj, 'topic');", + "window.getComputedStyle(elt);", + "window.getComputedStyle(elt, ':before');" + ], + invalid: [ + { + code: "Services.prefs.clearUserPref('browser.search.custom', false);", + errors: callError("clearUserPref takes only 1 parameter.") + }, + { + code: "Services.removeObserver('notification name', {}, false);", + errors: callError("removeObserver only takes 2 parameters.") + }, + { + code: "Services.removeObserver('notification name', {}, true);", + errors: callError("removeObserver only takes 2 parameters.") + }, + { + code: "Services.io.newURI('http://example.com', null, null);", + errors: callError("newURI's last parameters are optional.") + }, + { + code: "Services.io.newURI('http://example.com', 'utf8', null);", + errors: callError("newURI's last parameters are optional.") + }, + { + code: "Services.io.newURI('http://example.com', null);", + errors: callError("newURI's last parameters are optional.") + }, + { + code: "Services.io.newURI('http://example.com', '', '');", + errors: callError("newURI's last parameters are optional.") + }, + { + code: "Services.io.newURI('http://example.com', '');", + errors: callError("newURI's last parameters are optional.") + }, + { + code: "elt.addEventListener('click', handler, false);", + errors: callError( + "addEventListener's third parameter can be omitted when it's false.") + }, + { + code: "elt.removeEventListener('click', handler, false);", + errors: callError( + "removeEventListener's third parameter can be omitted when it's" + + " false.") + }, + { + code: "Services.obs.addObserver(this, 'topic', false);", + errors: callError( + "addObserver's third parameter can be omitted when it's" + + " false.") + }, + { + code: "Services.prefs.addObserver('branch', this, false);", + errors: callError( + "addObserver's third parameter can be omitted when it's" + + " false.") + }, + { + code: "array.appendElement(elt, false);", + errors: callError( + "appendElement's second parameter can be omitted when it's" + + " false.") + }, + { + code: "Services.obs.notifyObservers(obj, 'topic', null);", + errors: callError( + "notifyObservers's third parameter can be omitted.") + }, + { + code: "Services.obs.notifyObservers(obj, 'topic', '');", + errors: callError( + "notifyObservers's third parameter can be omitted.") + }, + { + code: "window.getComputedStyle(elt, null);", + errors: callError("getComputedStyle's second parameter can be omitted.") + }, + { + code: "window.getComputedStyle(elt, '');", + errors: callError("getComputedStyle's second parameter can be omitted.") + } + ] +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-removeEventListener.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-removeEventListener.js index 7d61cdf33d88..c3d6eff7444b 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-removeEventListener.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-removeEventListener.js @@ -8,6 +8,9 @@ // ------------------------------------------------------------------------------ var rule = require("../lib/rules/no-useless-removeEventListener"); +var RuleTester = require("eslint/lib/testers/rule-tester"); + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); // ------------------------------------------------------------------------------ // Tests @@ -19,64 +22,62 @@ function invalidCode(code) { return {code, errors: [{message, type: "CallExpression"}]}; } -exports.runTest = function(ruleTester) { - ruleTester.run("no-useless-removeEventListener", rule, { - valid: [ - // Listeners that aren't a function are always valid. - "elt.addEventListener('click', handler);", - "elt.addEventListener('click', handler, true);", - "elt.addEventListener('click', handler, {once: true});", +ruleTester.run("no-useless-removeEventListener", rule, { + valid: [ + // Listeners that aren't a function are always valid. + "elt.addEventListener('click', handler);", + "elt.addEventListener('click', handler, true);", + "elt.addEventListener('click', handler, {once: true});", - // Should not fail on empty functions. - "elt.addEventListener('click', function() {});", + // Should not fail on empty functions. + "elt.addEventListener('click', function() {});", - // Should not reject when removing a listener for another event. - "elt.addEventListener('click', function listener() {" + - " elt.removeEventListener('keypress', listener);" + - "});", + // Should not reject when removing a listener for another event. + "elt.addEventListener('click', function listener() {" + + " elt.removeEventListener('keypress', listener);" + + "});", - // Should not reject when there's another instruction before - // removeEventListener. - "elt.addEventListener('click', function listener() {" + - " elt.focus();" + - " elt.removeEventListener('click', listener);" + - "});", + // Should not reject when there's another instruction before + // removeEventListener. + "elt.addEventListener('click', function listener() {" + + " elt.focus();" + + " elt.removeEventListener('click', listener);" + + "});", - // Should not reject when wantsUntrusted is true. - "elt.addEventListener('click', function listener() {" + - " elt.removeEventListener('click', listener);" + - "}, false, true);", + // Should not reject when wantsUntrusted is true. + "elt.addEventListener('click', function listener() {" + + " elt.removeEventListener('click', listener);" + + "}, false, true);", - // Should not reject when there's a literal and a variable - "elt.addEventListener('click', function listener() {" + - " elt.removeEventListener(eventName, listener);" + - "});", + // Should not reject when there's a literal and a variable + "elt.addEventListener('click', function listener() {" + + " elt.removeEventListener(eventName, listener);" + + "});", - // Should not reject when there's 2 different variables - "elt.addEventListener(event1, function listener() {" + - " elt.removeEventListener(event2, listener);" + - "});" - ], - invalid: [ - invalidCode("elt.addEventListener('click', function listener() {" + - " elt.removeEventListener('click', listener);" + - "});"), - invalidCode("elt.addEventListener('click', function listener() {" + - " elt.removeEventListener('click', listener, true);" + - "}, true);"), - invalidCode("elt.addEventListener('click', function listener() {" + - " elt.removeEventListener('click', listener);" + - "}, {once: true});"), - invalidCode("elt.addEventListener('click', function listener() {" + - " /* Comment */" + - " elt.removeEventListener('click', listener);" + - "});"), - invalidCode("elt.addEventListener('click', function() {" + - " elt.removeEventListener('click', arguments.callee);" + - "});"), - invalidCode("elt.addEventListener(eventName, function listener() {" + - " elt.removeEventListener(eventName, listener);" + - "});") - ] - }); -}; + // Should not reject when there's 2 different variables + "elt.addEventListener(event1, function listener() {" + + " elt.removeEventListener(event2, listener);" + + "});" + ], + invalid: [ + invalidCode("elt.addEventListener('click', function listener() {" + + " elt.removeEventListener('click', listener);" + + "});"), + invalidCode("elt.addEventListener('click', function listener() {" + + " elt.removeEventListener('click', listener, true);" + + "}, true);"), + invalidCode("elt.addEventListener('click', function listener() {" + + " elt.removeEventListener('click', listener);" + + "}, {once: true});"), + invalidCode("elt.addEventListener('click', function listener() {" + + " /* Comment */" + + " elt.removeEventListener('click', listener);" + + "});"), + invalidCode("elt.addEventListener('click', function() {" + + " elt.removeEventListener('click', arguments.callee);" + + "});"), + invalidCode("elt.addEventListener(eventName, function listener() {" + + " elt.removeEventListener(eventName, listener);" + + "});") + ] +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/test-no-import-into-var-and-global.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/test-no-import-into-var-and-global.js index 3aecf5fe24b9..18f8374d8a50 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/tests/test-no-import-into-var-and-global.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/test-no-import-into-var-and-global.js @@ -8,6 +8,9 @@ // ------------------------------------------------------------------------------ var rule = require("../lib/rules/no-import-into-var-and-global"); +var RuleTester = require("eslint/lib/testers/rule-tester"); + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); // ------------------------------------------------------------------------------ // Tests @@ -18,18 +21,16 @@ const ExpectedError = { type: "CallExpression" }; -exports.runTest = function(ruleTester) { - ruleTester.run("no-import-into-var-and-global", rule, { - valid: [ - "var foo = Cu.import('fake', {});", - "var foo = Components.utils.import('fake', {});" - ], - invalid: [{ - code: "var foo = Cu.import('fake', this);", - errors: [ExpectedError] - }, { - code: "var foo = Cu.import('fake');", - errors: [ExpectedError] - }] - }); -}; +ruleTester.run("no-import-into-var-and-global", rule, { + valid: [ + "var foo = Cu.import('fake', {});", + "var foo = Components.utils.import('fake', {});" + ], + invalid: [{ + code: "var foo = Cu.import('fake', this);", + errors: [ExpectedError] + }, { + code: "var foo = Cu.import('fake');", + errors: [ExpectedError] + }] +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/test-no-single-arg-cu-import.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/test-no-single-arg-cu-import.js index 40754e19d266..f6d58cda47d2 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/tests/test-no-single-arg-cu-import.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/test-no-single-arg-cu-import.js @@ -8,6 +8,9 @@ // ------------------------------------------------------------------------------ var rule = require("../lib/rules/no-single-arg-cu-import"); +var RuleTester = require("eslint/lib/testers/rule-tester"); + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); // ------------------------------------------------------------------------------ // Tests @@ -18,14 +21,12 @@ const ExpectedError = { type: "CallExpression" }; -exports.runTest = function(ruleTester) { - ruleTester.run("no-single-arg-cu-import", rule, { - valid: [ - "Cu.import('fake', {});" - ], - invalid: [{ - code: "Cu.import('fake');", - errors: [ExpectedError] - }] - }); -}; +ruleTester.run("no-single-arg-cu-import", rule, { + valid: [ + "Cu.import('fake', {});" + ], + invalid: [{ + code: "Cu.import('fake');", + errors: [ExpectedError] + }] +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/test-run-all.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/test-run-all.js deleted file mode 100644 index 5ff9b5dbbf20..000000000000 --- a/tools/lint/eslint/eslint-plugin-mozilla/tests/test-run-all.js +++ /dev/null @@ -1,18 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -const RuleTester = require("eslint/lib/testers/rule-tester"); -const fs = require("fs"); - -var ruleTester = new RuleTester(); - -fs.readdir(__dirname, (err, files) => { - files.forEach(file => { - if (file != "test-run-all.js" && !file.endsWith("~")) { - console.log(`Running ${file}`); - require("./" + file).runTest(ruleTester); - } - }); -}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-default-preference-values.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-default-preference-values.js index 94547405545e..93131ab849bb 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-default-preference-values.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-default-preference-values.js @@ -8,6 +8,9 @@ // ------------------------------------------------------------------------------ var rule = require("../lib/rules/use-default-preference-values"); +var RuleTester = require("eslint/lib/testers/rule-tester"); + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); // ------------------------------------------------------------------------------ // Tests @@ -21,18 +24,16 @@ function invalidCode(code) { let types = ["Bool", "Char", "Float", "Int"]; let methods = types.map(type => "get" + type + "Pref"); -exports.runTest = function(ruleTester) { - ruleTester.run("use-ownerGlobal", rule, { - valid: [].concat( - methods.map(m => "blah = branch." + m + "('blah', true);"), - methods.map(m => "blah = branch." + m + "('blah');"), - methods.map(m => "try { canThrow();" + - " blah = branch." + m + "('blah'); } catch(e) {}") - ), +ruleTester.run("use-default-preference-values", rule, { + valid: [].concat( + methods.map(m => "blah = branch." + m + "('blah', true);"), + methods.map(m => "blah = branch." + m + "('blah');"), + methods.map(m => "try { canThrow();" + + " blah = branch." + m + "('blah'); } catch(e) {}") + ), - invalid: [].concat( - methods.map(m => - invalidCode("try { blah = branch." + m + "('blah'); } catch(e) {}")) - ) - }); -}; + invalid: [].concat( + methods.map(m => + invalidCode("try { blah = branch." + m + "('blah'); } catch(e) {}")) + ) +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-ownerGlobal.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-ownerGlobal.js index a54b1af9f25b..c90d67043288 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-ownerGlobal.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-ownerGlobal.js @@ -8,6 +8,9 @@ // ------------------------------------------------------------------------------ var rule = require("../lib/rules/use-ownerGlobal"); +var RuleTester = require("eslint/lib/testers/rule-tester"); + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); // ------------------------------------------------------------------------------ // Tests @@ -18,18 +21,16 @@ function invalidCode(code) { return {code, errors: [{message, type: "MemberExpression"}]}; } -exports.runTest = function(ruleTester) { - ruleTester.run("use-ownerGlobal", rule, { - valid: [ - "aEvent.target.ownerGlobal;", - "this.DOMPointNode.ownerGlobal.getSelection();", - "windowToMessageManager(node.ownerGlobal);" - ], - invalid: [ - invalidCode("aEvent.target.ownerDocument.defaultView;"), - invalidCode( - "this.DOMPointNode.ownerDocument.defaultView.getSelection();"), - invalidCode("windowToMessageManager(node.ownerDocument.defaultView);") - ] - }); -}; +ruleTester.run("use-ownerGlobal", rule, { + valid: [ + "aEvent.target.ownerGlobal;", + "this.DOMPointNode.ownerGlobal.getSelection();", + "windowToMessageManager(node.ownerGlobal);" + ], + invalid: [ + invalidCode("aEvent.target.ownerDocument.defaultView;"), + invalidCode( + "this.DOMPointNode.ownerDocument.defaultView.getSelection();"), + invalidCode("windowToMessageManager(node.ownerDocument.defaultView);") + ] +}); From fbd29db04b4ce057f5c25a2db01808b0c1c1d52a Mon Sep 17 00:00:00 2001 From: Mark Banner Date: Wed, 19 Apr 2017 12:17:14 +0100 Subject: [PATCH 24/65] Bug 1357702 - Make eslint-plugin-spidermonkey-js handle paths correct on Windows to avoid Unexpected character issues on ESLint. r=mossop MozReview-Commit-ID: LsQCgBOgceY --HG-- extra : rebase_source : 337037ad78c223139a3531a8ca9a68b13dbcb013 --- .../lib/processors/self-hosted.js | 5 +++++ tools/lint/eslint/eslint-plugin-spidermonkey-js/package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/lint/eslint/eslint-plugin-spidermonkey-js/lib/processors/self-hosted.js b/tools/lint/eslint/eslint-plugin-spidermonkey-js/lib/processors/self-hosted.js index 442923036aae..40172d171ebc 100644 --- a/tools/lint/eslint/eslint-plugin-spidermonkey-js/lib/processors/self-hosted.js +++ b/tools/lint/eslint/eslint-plugin-spidermonkey-js/lib/processors/self-hosted.js @@ -8,11 +8,16 @@ "use strict"; +var path = require("path"); + const selfHostedRegex = /js\/src\/(?:builtin|shell)\/.*?\.js$/; const macroRegex = /\s*\#(if|ifdef|else|elif|endif|include|define|undef).*/; module.exports = { preprocess(text, filename) { + if (path.win32) { + filename = filename.split(path.sep).join("/"); + } if (!selfHostedRegex.test(filename)) { return [text]; } diff --git a/tools/lint/eslint/eslint-plugin-spidermonkey-js/package.json b/tools/lint/eslint/eslint-plugin-spidermonkey-js/package.json index 68545709ee76..6216f33e2341 100644 --- a/tools/lint/eslint/eslint-plugin-spidermonkey-js/package.json +++ b/tools/lint/eslint/eslint-plugin-spidermonkey-js/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-spidermonkey-js", - "version": "0.1.0", + "version": "0.1.1", "description": "A collection of rules that help enforce JavaScript coding standard in the Mozilla SpiderMonkey project.", "keywords": [ "eslint", From 3b7b555b2e2c0d93d872b1f9d8cb6a343df8878a Mon Sep 17 00:00:00 2001 From: Scott Wu Date: Tue, 18 Apr 2017 17:42:03 +0800 Subject: [PATCH 25/65] Bug 1352331 - Swap the cancel and save buttons on edit profile dialog for Windows. r=lchang MozReview-Commit-ID: I3kvKClOIIO --HG-- rename : browser/extensions/formautofill/content/editProfile.css => browser/extensions/formautofill/skin/shared/editProfile.css extra : rebase_source : 07567a5e708d3a3660baeb16eb4565e630c4cad7 --- .../formautofill/content/editProfile.xhtml | 3 ++- .../formautofill/skin/linux/editProfile.css | 5 +++++ .../extensions/formautofill/skin/osx/editProfile.css | 5 +++++ .../{content => skin/shared}/editProfile.css | 0 .../formautofill/skin/windows/editProfile.css | 12 ++++++++++++ 5 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 browser/extensions/formautofill/skin/linux/editProfile.css create mode 100644 browser/extensions/formautofill/skin/osx/editProfile.css rename browser/extensions/formautofill/{content => skin/shared}/editProfile.css (100%) create mode 100644 browser/extensions/formautofill/skin/windows/editProfile.css diff --git a/browser/extensions/formautofill/content/editProfile.xhtml b/browser/extensions/formautofill/content/editProfile.xhtml index 9b8a6cf2f205..b537e0d02276 100644 --- a/browser/extensions/formautofill/content/editProfile.xhtml +++ b/browser/extensions/formautofill/content/editProfile.xhtml @@ -10,7 +10,8 @@ - loaded as a stacked subdialog. --> - + + diff --git a/browser/extensions/formautofill/skin/linux/editProfile.css b/browser/extensions/formautofill/skin/linux/editProfile.css new file mode 100644 index 000000000000..8281e2729586 --- /dev/null +++ b/browser/extensions/formautofill/skin/linux/editProfile.css @@ -0,0 +1,5 @@ +/* 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/. */ + +/* Linux specific rules */ diff --git a/browser/extensions/formautofill/skin/osx/editProfile.css b/browser/extensions/formautofill/skin/osx/editProfile.css new file mode 100644 index 000000000000..e22c07ec9533 --- /dev/null +++ b/browser/extensions/formautofill/skin/osx/editProfile.css @@ -0,0 +1,5 @@ +/* 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/. */ + +/* OSX specific rules */ diff --git a/browser/extensions/formautofill/content/editProfile.css b/browser/extensions/formautofill/skin/shared/editProfile.css similarity index 100% rename from browser/extensions/formautofill/content/editProfile.css rename to browser/extensions/formautofill/skin/shared/editProfile.css diff --git a/browser/extensions/formautofill/skin/windows/editProfile.css b/browser/extensions/formautofill/skin/windows/editProfile.css new file mode 100644 index 000000000000..7e473f379364 --- /dev/null +++ b/browser/extensions/formautofill/skin/windows/editProfile.css @@ -0,0 +1,12 @@ +/* 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/. */ + +/* The save button should be on the left and cancel on the right for Windows */ +#save { + order: 0; +} + +#cancel { + order: 1; +} From 4401e03681eb65547fe5a2b4278568c958f8d25b Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Thu, 20 Apr 2017 17:29:29 +1000 Subject: [PATCH 26/65] Bug 1355427 - Expectations adjustment followup. r=me --- layout/reftests/mathml/reftest-stylo.list | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/layout/reftests/mathml/reftest-stylo.list b/layout/reftests/mathml/reftest-stylo.list index 11d9fb1e2406..abe30f94c243 100644 --- a/layout/reftests/mathml/reftest-stylo.list +++ b/layout/reftests/mathml/reftest-stylo.list @@ -88,7 +88,7 @@ fails == mfenced-10.html mfenced-10.html == stretchy-largeop-1.html stretchy-largeop-1.html fails == stretchy-largeop-2.html stretchy-largeop-2.html == stretchy-largeop-3.html stretchy-largeop-3.html -== table-width-1.xhtml table-width-1.xhtml +fails == table-width-1.xhtml table-width-1.xhtml == table-width-2.html table-width-2.html fails == table-width-3.html table-width-3.html == table-width-4.html table-width-4.html @@ -127,7 +127,7 @@ fails-if(http.oscpu=="Linux\u0020x86_64") random-if(winWidget&&!/^Windows\x20NT\ == mathbackground-3.xml mathbackground-3.xml == mathbackground-4.xml mathbackground-4.xml == mstyle-1.xhtml mstyle-1.xhtml -== mstyle-2.xhtml mstyle-2.xhtml +fails == mstyle-2.xhtml mstyle-2.xhtml == mstyle-3.xhtml mstyle-3.xhtml == mstyle-4.xhtml mstyle-4.xhtml == mstyle-5.xhtml mstyle-5.xhtml From b35beae16dba28bfe25b109b771d9f59e2315b83 Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Thu, 20 Apr 2017 01:55:33 -0500 Subject: [PATCH 27/65] servo: Merge #16531 - Eliminate ScrollRootId (from mrobinson:clip-id); r=glennw Just use WebRender's ClipId directly. This will allow us to create and use ReferenceFrames in the future, if we need to do that. It will also make it easier to have Servo responsible for creating the root scrolling area, which will allow removing some old hacks in the future. --- - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). - [ ] There are tests for these changes OR - [x] These changes do not require tests because they should not change behavior. Source-Repo: https://github.com/servo/servo Source-Revision: 6e05a903afe81af5a45067dde4f9af26a2ea4be2 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : ed3c05a3a6ad1de7c189632886473e8b9b294565 --- servo/Cargo.lock | 2 + servo/components/compositing/compositor.rs | 42 ++--- .../compositing/compositor_thread.rs | 3 +- .../components/constellation/constellation.rs | 5 +- servo/components/gfx/display_list/mod.rs | 45 +++--- servo/components/gfx_traits/lib.rs | 143 ++++++------------ servo/components/layout/context.rs | 4 + .../components/layout/display_list_builder.rs | 115 ++++++++------ servo/components/layout/flow.rs | 20 ++- servo/components/layout/fragment.rs | 25 +-- servo/components/layout/query.rs | 11 +- servo/components/layout/traversal.rs | 2 +- servo/components/layout/webrender_helpers.rs | 30 +--- servo/components/layout_thread/lib.rs | 16 +- servo/components/msg/constellation_msg.rs | 4 + servo/components/script/dom/document.rs | 6 +- servo/components/script/dom/window.rs | 10 +- .../script_layout_interface/Cargo.toml | 1 + .../components/script_layout_interface/lib.rs | 1 + .../components/script_layout_interface/rpc.rs | 4 +- .../script_layout_interface/wrapper_traits.rs | 8 +- servo/components/script_traits/Cargo.toml | 1 + servo/components/script_traits/lib.rs | 5 +- servo/components/script_traits/script_msg.rs | 4 +- 24 files changed, 226 insertions(+), 281 deletions(-) diff --git a/servo/Cargo.lock b/servo/Cargo.lock index e42926a39caa..119302c8d0e3 100644 --- a/servo/Cargo.lock +++ b/servo/Cargo.lock @@ -2339,6 +2339,7 @@ dependencies = [ "selectors 0.18.0", "servo_url 0.0.1", "style 0.0.1", + "webrender_traits 0.35.0 (git+https://github.com/servo/webrender)", ] [[package]] @@ -2383,6 +2384,7 @@ dependencies = [ "style_traits 0.0.1", "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "webrender_traits 0.35.0 (git+https://github.com/servo/webrender)", "webvr_traits 0.0.1", ] diff --git a/servo/components/compositing/compositor.rs b/servo/components/compositing/compositor.rs index f76ee24b0399..96a44a7dc04f 100644 --- a/servo/components/compositing/compositor.rs +++ b/servo/components/compositing/compositor.rs @@ -12,7 +12,7 @@ use euclid::point::TypedPoint2D; use euclid::rect::TypedRect; use euclid::scale_factor::ScaleFactor; use euclid::size::TypedSize2D; -use gfx_traits::{Epoch, ScrollRootId}; +use gfx_traits::Epoch; use gleam::gl; use image::{DynamicImage, ImageFormat, RgbImage}; use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory}; @@ -39,7 +39,7 @@ use style_traits::viewport::ViewportConstraints; use time::{precise_time_ns, precise_time_s}; use touch::{TouchHandler, TouchAction}; use webrender; -use webrender_traits::{self, LayoutPoint, ScrollEventPhase, ClipId, ScrollLocation}; +use webrender_traits::{self, ClipId, LayoutPoint, ScrollEventPhase, ScrollLocation}; use windowing::{self, MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg}; #[derive(Debug, PartialEq)] @@ -72,19 +72,6 @@ impl ConvertPipelineIdFromWebRender for webrender_traits::PipelineId { } } -trait ConvertScrollRootIdFromWebRender { - fn from_webrender(&self) -> ScrollRootId; -} - -impl ConvertScrollRootIdFromWebRender for u64 { - fn from_webrender(&self) -> ScrollRootId { - // This conversion is lossy on 32 bit platforms, - // but we only actually use the bottom 32 bits - // on Servo anyway. - ScrollRootId(*self as usize) - } -} - /// Holds the state when running reftests that determines when it is /// safe to save the output image. #[derive(Copy, Clone, PartialEq)] @@ -505,9 +492,9 @@ impl IOCompositor { self.title_for_main_frame(); } - (Msg::ScrollFragmentPoint(pipeline_id, scroll_root_id, point, _), + (Msg::ScrollFragmentPoint(scroll_root_id, point, _), ShutdownState::NotShuttingDown) => { - self.scroll_fragment_to_point(pipeline_id, scroll_root_id, point); + self.scroll_fragment_to_point(scroll_root_id, point); } (Msg::MoveTo(point), @@ -793,16 +780,7 @@ impl IOCompositor { self.composition_request = CompositionRequest::DelayedComposite(timestamp); } - fn scroll_fragment_to_point(&mut self, - pipeline_id: PipelineId, - scroll_root_id: ScrollRootId, - point: Point2D) { - let id = if scroll_root_id.0 == 0 { - ClipId::root_scroll_node(pipeline_id.to_webrender()) - } else { - ClipId::new(scroll_root_id.0 as u64, pipeline_id.to_webrender()) - }; - + fn scroll_fragment_to_point(&mut self, id: ClipId, point: Point2D) { self.webrender_api.scroll_node_with_id(LayoutPoint::from_untyped(&point), id); } @@ -1395,13 +1373,13 @@ impl IOCompositor { fn send_viewport_rects(&self) { let mut stacking_context_scroll_states_per_pipeline = HashMap::new(); for scroll_layer_state in self.webrender_api.get_scroll_node_state() { - let external_id = match scroll_layer_state.id.external_id() { - Some(id) => id, - None => continue, - }; + if scroll_layer_state.id.external_id().is_none() && + scroll_layer_state.id.is_root_scroll_node() { + continue; + } let stacking_context_scroll_state = StackingContextScrollState { - scroll_root_id: external_id.from_webrender(), + scroll_root_id: scroll_layer_state.id, scroll_offset: scroll_layer_state.scroll_offset.to_untyped(), }; diff --git a/servo/components/compositing/compositor_thread.rs b/servo/components/compositing/compositor_thread.rs index e475bba05149..67d98d9e5e57 100644 --- a/servo/components/compositing/compositor_thread.rs +++ b/servo/components/compositing/compositor_thread.rs @@ -8,7 +8,6 @@ use SendableFrameTree; use compositor::CompositingReason; use euclid::point::Point2D; use euclid::size::Size2D; -use gfx_traits::ScrollRootId; use ipc_channel::ipc::IpcSender; use msg::constellation_msg::{Key, KeyModifiers, KeyState, PipelineId}; use net_traits::image::base::Image; @@ -73,7 +72,7 @@ pub enum Msg { ShutdownComplete, /// Scroll a page in a window - ScrollFragmentPoint(PipelineId, ScrollRootId, Point2D, bool), + ScrollFragmentPoint(webrender_traits::ClipId, Point2D, bool), /// Alerts the compositor that the current page has changed its title. ChangePageTitle(PipelineId, Option), /// Alerts the compositor that the current page has changed its URL. diff --git a/servo/components/constellation/constellation.rs b/servo/components/constellation/constellation.rs index 31942533990b..b2328c8bd08a 100644 --- a/servo/components/constellation/constellation.rs +++ b/servo/components/constellation/constellation.rs @@ -1036,9 +1036,8 @@ impl Constellation self.handle_alert(pipeline_id, message, sender); } - FromScriptMsg::ScrollFragmentPoint(pipeline_id, scroll_root_id, point, smooth) => { - self.compositor_proxy.send(ToCompositorMsg::ScrollFragmentPoint(pipeline_id, - scroll_root_id, + FromScriptMsg::ScrollFragmentPoint(scroll_root_id, point, smooth) => { + self.compositor_proxy.send(ToCompositorMsg::ScrollFragmentPoint(scroll_root_id, point, smooth)); } diff --git a/servo/components/gfx/display_list/mod.rs b/servo/components/gfx/display_list/mod.rs index 4113193fc677..205b4071589c 100644 --- a/servo/components/gfx/display_list/mod.rs +++ b/servo/components/gfx/display_list/mod.rs @@ -19,7 +19,7 @@ use euclid::{Matrix4D, Point2D, Rect, Size2D}; use euclid::num::{One, Zero}; use euclid::rect::TypedRect; use euclid::side_offsets::SideOffsets2D; -use gfx_traits::{ScrollRootId, StackingContextId}; +use gfx_traits::StackingContextId; use gfx_traits::print_tree::PrintTree; use ipc_channel::ipc::IpcSharedMemory; use msg::constellation_msg::PipelineId; @@ -34,7 +34,7 @@ use style::computed_values::{border_style, filter, image_rendering, mix_blend_mo use style_traits::cursor::Cursor; use text::TextRun; use text::glyph::ByteIndex; -use webrender_traits::{self, ColorF, GradientStop, ScrollPolicy, WebGLContextId}; +use webrender_traits::{self, ClipId, ColorF, GradientStop, ScrollPolicy, WebGLContextId}; pub use style::dom::OpaqueNode; @@ -377,7 +377,7 @@ pub struct StackingContext { pub scroll_policy: ScrollPolicy, /// The id of the parent scrolling area that contains this StackingContext. - pub parent_scroll_id: ScrollRootId, + pub parent_scroll_id: ClipId, } impl StackingContext { @@ -393,7 +393,7 @@ impl StackingContext { transform: Option>, perspective: Option>, scroll_policy: ScrollPolicy, - parent_scroll_id: ScrollRootId) + parent_scroll_id: ClipId) -> StackingContext { StackingContext { id: id, @@ -411,8 +411,8 @@ impl StackingContext { } #[inline] - pub fn root() -> StackingContext { - StackingContext::new(StackingContextId::new(0), + pub fn root(pipeline_id: PipelineId) -> StackingContext { + StackingContext::new(StackingContextId::root(), StackingContextType::Real, &Rect::zero(), &Rect::zero(), @@ -422,11 +422,11 @@ impl StackingContext { None, None, ScrollPolicy::Scrollable, - ScrollRootId::root()) + pipeline_id.root_scroll_node()) } - pub fn to_display_list_items(self) -> (DisplayItem, DisplayItem) { - let mut base_item = BaseDisplayItem::empty(); + pub fn to_display_list_items(self, pipeline_id: PipelineId) -> (DisplayItem, DisplayItem) { + let mut base_item = BaseDisplayItem::empty(pipeline_id); base_item.stacking_context_id = self.id; base_item.scroll_root_id = self.parent_scroll_id; @@ -495,11 +495,12 @@ impl fmt::Debug for StackingContext { /// Defines a stacking context. #[derive(Clone, Debug, HeapSizeOf, Deserialize, Serialize)] pub struct ScrollRoot { - /// The unique ID of this ScrollRoot. - pub id: ScrollRootId, + /// The WebRender clip id of this scroll root based on the source of this clip + /// and information about the fragment. + pub id: ClipId, /// The unique ID of the parent of this ScrollRoot. - pub parent_id: ScrollRootId, + pub parent_id: ClipId, /// The position of this scroll root's frame in the parent stacking context. pub clip: ClippingRegion, @@ -509,9 +510,9 @@ pub struct ScrollRoot { } impl ScrollRoot { - pub fn to_push(&self) -> DisplayItem { + pub fn to_push(&self, pipeline_id: PipelineId) -> DisplayItem { DisplayItem::PushScrollRoot(box PushScrollRootItem { - base: BaseDisplayItem::empty(), + base: BaseDisplayItem::empty(pipeline_id), scroll_root: self.clone(), }) } @@ -555,7 +556,7 @@ pub struct BaseDisplayItem { pub stacking_context_id: StackingContextId, /// The id of the scroll root this item belongs to. - pub scroll_root_id: ScrollRootId, + pub scroll_root_id: ClipId, } impl BaseDisplayItem { @@ -565,7 +566,7 @@ impl BaseDisplayItem { clip: &ClippingRegion, section: DisplayListSection, stacking_context_id: StackingContextId, - scroll_root_id: ScrollRootId) + scroll_root_id: ClipId) -> BaseDisplayItem { // Detect useless clipping regions here and optimize them to `ClippingRegion::max()`. // The painting backend may want to optimize out clipping regions and this makes it easier @@ -585,7 +586,7 @@ impl BaseDisplayItem { } #[inline(always)] - pub fn empty() -> BaseDisplayItem { + pub fn empty(pipeline_id: PipelineId) -> BaseDisplayItem { BaseDisplayItem { bounds: TypedRect::zero(), metadata: DisplayItemMetadata { @@ -595,7 +596,7 @@ impl BaseDisplayItem { clip: ClippingRegion::max(), section: DisplayListSection::Content, stacking_context_id: StackingContextId::root(), - scroll_root_id: ScrollRootId::root(), + scroll_root_id: pipeline_id.root_scroll_node(), } } } @@ -866,7 +867,6 @@ pub struct ImageDisplayItem { #[derive(Clone, HeapSizeOf, Deserialize, Serialize)] pub struct WebGLDisplayItem { pub base: BaseDisplayItem, - #[ignore_heap_size_of = "Defined in webrender_traits"] pub context_id: WebGLContextId, } @@ -931,11 +931,9 @@ pub struct ImageBorder { pub fill: bool, /// How to repeat or stretch horizontal edges (border-image-repeat). - #[ignore_heap_size_of = "WebRender traits type, and tiny"] pub repeat_horizontal: webrender_traits::RepeatMode, /// How to repeat or stretch vertical edges (border-image-repeat). - #[ignore_heap_size_of = "WebRender traits type, and tiny"] pub repeat_vertical: webrender_traits::RepeatMode, } @@ -1136,7 +1134,7 @@ impl DisplayItem { } } - pub fn scroll_root_id(&self) -> ScrollRootId { + pub fn scroll_root_id(&self) -> ClipId { self.base().scroll_root_id } @@ -1262,7 +1260,6 @@ pub struct WebRenderImageInfo { pub width: u32, pub height: u32, pub format: PixelFormat, - #[ignore_heap_size_of = "WebRender traits type, and tiny"] pub key: Option, } @@ -1279,7 +1276,7 @@ impl WebRenderImageInfo { } /// The type of the scroll offset list. This is only populated if WebRender is in use. -pub type ScrollOffsetMap = HashMap>; +pub type ScrollOffsetMap = HashMap>; pub trait SimpleMatrixDetection { diff --git a/servo/components/gfx_traits/lib.rs b/servo/components/gfx_traits/lib.rs index 0dae3d6fff14..14f168671d7f 100644 --- a/servo/components/gfx_traits/lib.rs +++ b/servo/components/gfx_traits/lib.rs @@ -19,18 +19,6 @@ pub mod print_tree; use range::RangeIndex; use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering}; -/// The next ID that will be used for a special stacking context. -/// -/// A special stacking context is a stacking context that is one of (a) the outer stacking context -/// of an element with `overflow: scroll`; (b) generated content; (c) both (a) and (b). -static NEXT_SPECIAL_STACKING_CONTEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT; - -/// If none of the bits outside this mask are set, the stacking context is a special stacking -/// context. -/// -/// Note that we assume that the top 16 bits of the address space are unused on the platform. -const SPECIAL_STACKING_CONTEXT_ID_MASK: usize = 0xffff; - /// A newtype struct for denoting the age of messages; prevents race conditions. #[derive(PartialEq, Eq, Debug, Copy, Clone, PartialOrd, Ord, Deserialize, Serialize)] pub struct Epoch(pub u32); @@ -46,89 +34,29 @@ impl Epoch { pub struct StackingContextId( /// The identifier for this StackingContext, derived from the Flow's memory address /// and fragment type. As a space optimization, these are combined into a single word. - usize + u64 ); impl StackingContextId { - #[inline] - pub fn new(id: usize) -> StackingContextId { - StackingContextId::new_of_type(id, FragmentType::FragmentBody) - } - - /// Returns a new stacking context ID for a special stacking context. - fn next_special_id() -> usize { - // We shift this left by 2 to make room for the fragment type ID. - ((NEXT_SPECIAL_STACKING_CONTEXT_ID.fetch_add(1, Ordering::SeqCst) + 1) << 2) & - SPECIAL_STACKING_CONTEXT_ID_MASK - } - - #[inline] - pub fn new_of_type(id: usize, fragment_type: FragmentType) -> StackingContextId { - debug_assert_eq!(id & (fragment_type as usize), 0); - if fragment_type == FragmentType::FragmentBody { - StackingContextId(id) - } else { - StackingContextId(StackingContextId::next_special_id() | (fragment_type as usize)) - } - } - /// Returns the stacking context ID for the outer document/layout root. #[inline] pub fn root() -> StackingContextId { StackingContextId(0) } + + /// Returns a new sacking context id with the given numeric id. + #[inline] + pub fn new(id: u64) -> StackingContextId { + StackingContextId(id) + } } -/// A unique ID for every scrolling root. -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, HeapSizeOf, PartialEq, Serialize)] -pub struct ScrollRootId( - /// The identifier for this StackingContext, derived from the Flow's memory address - /// and fragment type. As a space optimization, these are combined into a single word. - pub usize -); - -impl ScrollRootId { - /// Returns a new stacking context ID for a special stacking context. - fn next_special_id() -> usize { - // We shift this left by 2 to make room for the fragment type ID. - ((NEXT_SPECIAL_STACKING_CONTEXT_ID.fetch_add(1, Ordering::SeqCst) + 1) << 2) & - SPECIAL_STACKING_CONTEXT_ID_MASK - } - - #[inline] - pub fn new_of_type(id: usize, fragment_type: FragmentType) -> ScrollRootId { - debug_assert_eq!(id & (fragment_type as usize), 0); - if fragment_type == FragmentType::FragmentBody { - ScrollRootId(id) - } else { - ScrollRootId(ScrollRootId::next_special_id() | (fragment_type as usize)) - } - } - - /// Returns the stacking context ID for the outer document/layout root. - #[inline] - pub fn root() -> ScrollRootId { - ScrollRootId(0) - } - - /// Returns true if this is a special stacking context. - /// - /// A special stacking context is a stacking context that is one of (a) the outer stacking - /// context of an element with `overflow: scroll`; (b) generated content; (c) both (a) and (b). - #[inline] - pub fn is_special(&self) -> bool { - (self.0 & !SPECIAL_STACKING_CONTEXT_ID_MASK) == 0 - } - - #[inline] - pub fn id(&self) -> usize { - self.0 & !3 - } - - #[inline] - pub fn fragment_type(&self) -> FragmentType { - FragmentType::from_usize(self.0 & 3) - } +int_range_index! { + #[derive(Deserialize, Serialize)] + #[doc = "An index that refers to a byte offset in a text run. This could \ + point to the middle of a glyph."] + #[derive(HeapSizeOf)] + struct ByteIndex(isize) } /// The type of fragment that a stacking context represents. @@ -146,22 +74,37 @@ pub enum FragmentType { AfterPseudoContent, } -impl FragmentType { - #[inline] - pub fn from_usize(n: usize) -> FragmentType { - debug_assert!(n < 3); - match n { - 0 => FragmentType::FragmentBody, - 1 => FragmentType::BeforePseudoContent, - _ => FragmentType::AfterPseudoContent, - } +/// The next ID that will be used for a special stacking context. +/// +/// A special stacking context is a stacking context that is one of (a) the outer stacking context +/// of an element with `overflow: scroll`; (b) generated content; (c) both (a) and (b). +static NEXT_SPECIAL_STACKING_CONTEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT; + +/// If none of the bits outside this mask are set, the stacking context is a special stacking +/// context. +/// +/// Note that we assume that the top 16 bits of the address space are unused on the platform. +const SPECIAL_STACKING_CONTEXT_ID_MASK: usize = 0xffff; + +/// Returns a new stacking context ID for a special stacking context. +fn next_special_id() -> usize { + // We shift this left by 2 to make room for the fragment type ID. + ((NEXT_SPECIAL_STACKING_CONTEXT_ID.fetch_add(1, Ordering::SeqCst) + 1) << 2) & + SPECIAL_STACKING_CONTEXT_ID_MASK +} + +pub fn combine_id_with_fragment_type(id: usize, fragment_type: FragmentType) -> usize { + debug_assert_eq!(id & (fragment_type as usize), 0); + if fragment_type == FragmentType::FragmentBody { + id + } else { + next_special_id() | (fragment_type as usize) } } -int_range_index! { - #[derive(Deserialize, Serialize)] - #[doc = "An index that refers to a byte offset in a text run. This could \ - point to the middle of a glyph."] - #[derive(HeapSizeOf)] - struct ByteIndex(isize) +pub fn node_id_from_clip_id(id: usize) -> Option { + if (id & !SPECIAL_STACKING_CONTEXT_ID_MASK) != 0 { + return Some((id & !3) as usize); + } + None } diff --git a/servo/components/layout/context.rs b/servo/components/layout/context.rs index 72be25557201..214061e276fa 100644 --- a/servo/components/layout/context.rs +++ b/servo/components/layout/context.rs @@ -9,6 +9,7 @@ use gfx::display_list::{WebRenderImageInfo, OpaqueNode}; use gfx::font_cache_thread::FontCacheThread; use gfx::font_context::FontContext; use heapsize::HeapSizeOf; +use msg::constellation_msg::PipelineId; use net_traits::image_cache::{CanRequestImages, ImageCache, ImageState}; use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder}; use opaque_node::OpaqueNodeMethods; @@ -76,6 +77,9 @@ pub fn heap_size_of_persistent_local_context() -> usize { /// Layout information shared among all workers. This must be thread-safe. pub struct LayoutContext<'a> { + /// The pipeline id of this LayoutContext. + pub id: PipelineId, + /// Bits shared by the layout and style system. pub style_context: SharedStyleContext<'a>, diff --git a/servo/components/layout/display_list_builder.rs b/servo/components/layout/display_list_builder.rs index bb69af42b688..fdd7692c1f1b 100644 --- a/servo/components/layout/display_list_builder.rs +++ b/servo/components/layout/display_list_builder.rs @@ -29,7 +29,7 @@ use gfx::display_list::{GradientDisplayItem, IframeDisplayItem, ImageDisplayItem use gfx::display_list::{LineDisplayItem, OpaqueNode}; use gfx::display_list::{SolidColorDisplayItem, ScrollRoot, StackingContext, StackingContextType}; use gfx::display_list::{TextDisplayItem, TextOrientation, WebGLDisplayItem, WebRenderImageInfo}; -use gfx_traits::{ScrollRootId, StackingContextId}; +use gfx_traits::{combine_id_with_fragment_type, FragmentType, StackingContextId}; use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT}; use ipc_channel::ipc; use list_item::ListItemFlow; @@ -38,6 +38,7 @@ use msg::constellation_msg::PipelineId; use net_traits::image::base::PixelFormat; use net_traits::image_cache::UsePlaceholder; use range::Range; +use script_layout_interface::wrapper_traits::PseudoElementType; use servo_config::opts; use servo_geometry::max_rect; use servo_url::ServoUrl; @@ -63,7 +64,7 @@ use style::values::specified::{HorizontalDirection, VerticalDirection}; use style_traits::CSSPixel; use style_traits::cursor::Cursor; use table_cell::CollapsedBordersForCell; -use webrender_traits::{ColorF, GradientStop, RepeatMode, ScrollPolicy}; +use webrender_traits::{ColorF, ClipId, GradientStop, RepeatMode, ScrollPolicy}; trait ResolvePercentage { fn resolve(&self, length: u32) -> u32; @@ -152,7 +153,7 @@ pub struct DisplayListBuildState<'a> { pub root_stacking_context: StackingContext, pub items: HashMap>, stacking_context_info: HashMap, - pub scroll_root_parents: HashMap, + pub scroll_root_parents: HashMap, pub processing_scroll_root_element: bool, /// The current stacking context id, used to keep track of state when building. @@ -161,12 +162,12 @@ pub struct DisplayListBuildState<'a> { /// The current scroll root id, used to keep track of state when /// recursively building and processing the display list. - pub current_scroll_root_id: ScrollRootId, + pub current_scroll_root_id: ClipId, /// The scroll root id of the first ancestor which defines a containing block. /// This is necessary because absolutely positioned items should be clipped /// by their containing block's scroll root. - pub containing_block_scroll_root_id: ScrollRootId, + pub containing_block_scroll_root_id: ClipId, /// Vector containing iframe sizes, used to inform the constellation about /// new iframe sizes @@ -185,14 +186,14 @@ impl<'a> DisplayListBuildState<'a> { pub fn new(layout_context: &'a LayoutContext) -> DisplayListBuildState<'a> { DisplayListBuildState { layout_context: layout_context, - root_stacking_context: StackingContext::root(), + root_stacking_context: StackingContext::root(layout_context.id), items: HashMap::new(), stacking_context_info: HashMap::new(), scroll_root_parents: HashMap::new(), processing_scroll_root_element: false, current_stacking_context_id: StackingContextId::root(), - current_scroll_root_id: ScrollRootId::root(), - containing_block_scroll_root_id: ScrollRootId::root(), + current_scroll_root_id: layout_context.id.root_scroll_node(), + containing_block_scroll_root_id: layout_context.id.root_scroll_node(), iframe_sizes: Vec::new(), clip_stack: Vec::new(), containing_block_clip_stack: Vec::new(), @@ -213,7 +214,7 @@ impl<'a> DisplayListBuildState<'a> { info.children.push(stacking_context); } - fn has_scroll_root(&mut self, id: ScrollRootId) -> bool { + fn has_scroll_root(&mut self, id: ClipId) -> bool { self.scroll_root_parents.contains_key(&id) } @@ -225,9 +226,9 @@ impl<'a> DisplayListBuildState<'a> { info.scroll_roots.push(scroll_root); } - fn parent_scroll_root_id(&self, scroll_root_id: ScrollRootId) -> ScrollRootId { - if scroll_root_id == ScrollRootId::root() { - return ScrollRootId::root() + fn parent_scroll_root_id(&self, scroll_root_id: ClipId) -> ClipId { + if scroll_root_id.is_root_scroll_node() { + return scroll_root_id; } debug_assert!(self.scroll_root_parents.contains_key(&scroll_root_id)); @@ -262,7 +263,8 @@ impl<'a> DisplayListBuildState<'a> { pub fn to_display_list(mut self) -> DisplayList { let mut list = Vec::new(); - let root_context = mem::replace(&mut self.root_stacking_context, StackingContext::root()); + let root_context = mem::replace(&mut self.root_stacking_context, + StackingContext::root(self.layout_context.id)); self.to_display_list_for_stacking_context(&mut list, root_context); @@ -283,13 +285,14 @@ impl<'a> DisplayListBuildState<'a> { info.children.sort(); + let pipeline_id = self.layout_context.id; if stacking_context.context_type != StackingContextType::Real { - list.extend(info.scroll_roots.into_iter().map(|root| root.to_push())); + list.extend(info.scroll_roots.into_iter().map(|root| root.to_push(pipeline_id))); self.to_display_list_for_items(list, child_items, info.children); } else { - let (push_item, pop_item) = stacking_context.to_display_list_items(); + let (push_item, pop_item) = stacking_context.to_display_list_items(pipeline_id); list.push(push_item); - list.extend(info.scroll_roots.into_iter().map(|root| root.to_push())); + list.extend(info.scroll_roots.into_iter().map(|root| root.to_push(pipeline_id))); self.to_display_list_for_items(list, child_items, info.children); list.push(pop_item); } @@ -348,6 +351,12 @@ impl<'a> DisplayListBuildState<'a> { /// The logical width of an insertion point: at the moment, a one-pixel-wide line. const INSERTION_POINT_LOGICAL_WIDTH: Au = Au(1 * AU_PER_PX); +pub enum IdType { + StackingContext, + OverflowClip, + CSSClip, +} + pub trait FragmentDisplayListBuilding { /// Adds the display items necessary to paint the background of this fragment to the display /// list if necessary. @@ -495,12 +504,16 @@ pub trait FragmentDisplayListBuilding { base_flow: &BaseFlow, scroll_policy: ScrollPolicy, mode: StackingContextCreationMode, - parent_scroll_id: ScrollRootId) + parent_scroll_id: ClipId) -> StackingContext; /// The id of stacking context this fragment would create. fn stacking_context_id(&self) -> StackingContextId; + + fn unique_id(&self, id_type: IdType) -> u64; + + fn fragment_type(&self) -> FragmentType; } fn handle_overlapping_radii(size: &Size2D, radii: &BorderRadii) -> BorderRadii { @@ -1653,7 +1666,7 @@ impl FragmentDisplayListBuilding for Fragment { } fn stacking_context_id(&self) -> StackingContextId { - StackingContextId::new_of_type(self.node.id() as usize, self.fragment_type()) + StackingContextId::new(self.unique_id(IdType::StackingContext)) } fn create_stacking_context(&self, @@ -1661,7 +1674,7 @@ impl FragmentDisplayListBuilding for Fragment { base_flow: &BaseFlow, scroll_policy: ScrollPolicy, mode: StackingContextCreationMode, - parent_scroll_id: ScrollRootId) + parent_scroll_id: ClipId) -> StackingContext { let border_box = self.stacking_relative_border_box(&base_flow.stacking_relative_position, @@ -1839,6 +1852,24 @@ impl FragmentDisplayListBuilding for Fragment { })); } + fn unique_id(&self, id_type: IdType) -> u64 { + let fragment_type = self.fragment_type(); + let id = match id_type { + IdType::StackingContext | IdType::OverflowClip => self.node.id() as usize, + IdType::CSSClip => self as *const _ as usize, + }; + combine_id_with_fragment_type(id, fragment_type) as u64 + } + + fn fragment_type(&self) -> FragmentType { + match self.pseudo { + PseudoElementType::Normal => FragmentType::FragmentBody, + PseudoElementType::Before(_) => FragmentType::BeforePseudoContent, + PseudoElementType::After(_) => FragmentType::AfterPseudoContent, + PseudoElementType::DetailsSummary(_) => FragmentType::FragmentBody, + PseudoElementType::DetailsContent(_) => FragmentType::FragmentBody, + } + } } pub trait BlockFlowDisplayListBuilding { @@ -1851,7 +1882,7 @@ pub trait BlockFlowDisplayListBuilding { state: &mut DisplayListBuildState, preserved_state: &mut PreservedDisplayListState, stacking_context_type: BlockStackingContextType) - -> ScrollRootId; + -> ClipId; fn setup_scroll_root_for_overflow(&mut self, state: &mut DisplayListBuildState, preserved_state: &mut PreservedDisplayListState, @@ -1862,11 +1893,11 @@ pub trait BlockFlowDisplayListBuilding { stacking_relative_border_box: &Rect); fn create_pseudo_stacking_context_for_block(&mut self, parent_stacking_context_id: StackingContextId, - parent_scroll_root_id: ScrollRootId, + parent_scroll_root_id: ClipId, state: &mut DisplayListBuildState); fn create_real_stacking_context_for_block(&mut self, parent_stacking_context_id: StackingContextId, - parent_scroll_root_id: ScrollRootId, + parent_scroll_root_id: ClipId, state: &mut DisplayListBuildState); fn build_display_list_for_block(&mut self, state: &mut DisplayListBuildState, @@ -1880,8 +1911,8 @@ pub trait BlockFlowDisplayListBuilding { /// TODO(mrobinson): It would be nice to use RAII here to avoid having to call restore. pub struct PreservedDisplayListState { stacking_context_id: StackingContextId, - scroll_root_id: ScrollRootId, - containing_block_scroll_root_id: ScrollRootId, + scroll_root_id: ClipId, + containing_block_scroll_root_id: ClipId, clips_pushed: usize, containing_block_clips_pushed: usize, } @@ -2041,7 +2072,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow { state: &mut DisplayListBuildState, preserved_state: &mut PreservedDisplayListState, stacking_context_type: BlockStackingContextType) - -> ScrollRootId { + -> ClipId { // If this block is absolutely positioned, we should be clipped and positioned by // the scroll root of our nearest ancestor that establishes a containing block. let containing_scroll_root_id = match self.positioning() { @@ -2056,7 +2087,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow { } _ => state.current_scroll_root_id, }; - self.base.scroll_root_id = containing_scroll_root_id; + self.base.scroll_root_id = Some(containing_scroll_root_id); let coordinate_system = if self.fragment.establishes_stacking_context() { CoordinateSystem::Own @@ -2108,11 +2139,11 @@ impl BlockFlowDisplayListBuilding for BlockFlow { return; } - let new_scroll_root_id = ScrollRootId::new_of_type(self.fragment.node.id() as usize, - self.fragment.fragment_type()); // If we already have a scroll root for this flow, just return. This can happen // when fragments map to more than one flow, such as in the case of table // wrappers. We just accept the first scroll root in that case. + let new_scroll_root_id = ClipId::new(self.fragment.unique_id(IdType::OverflowClip), + state.layout_context.id.to_webrender()); if state.has_scroll_root(new_scroll_root_id) { return; } @@ -2148,17 +2179,18 @@ impl BlockFlowDisplayListBuilding for BlockFlow { clip.intersect_with_rounded_rect(&clip_rect, &radii) } + let parent_id = self.scroll_root_id(state.layout_context.id); state.add_scroll_root( ScrollRoot { id: new_scroll_root_id, - parent_id: self.base.scroll_root_id, + parent_id: parent_id, clip: clip, content_rect: Rect::new(content_box.origin, content_size), }, self.base.stacking_context_id ); - self.base.scroll_root_id = new_scroll_root_id; + self.base.scroll_root_id = Some(new_scroll_root_id); state.current_scroll_root_id = new_scroll_root_id; } @@ -2186,9 +2218,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow { // use the fragment address to do the same for CSS clipping. // TODO(mrobinson): This should be more resilient while maintaining the space // efficiency of ScrollRootId. - let fragment_id = &mut self.fragment as *mut _; - let new_scroll_root_id = ScrollRootId::new_of_type(fragment_id as usize, - self.fragment.fragment_type()); + let new_scroll_root_id = ClipId::new(self.fragment.unique_id(IdType::CSSClip), + state.layout_context.id.to_webrender()); // If we already have a scroll root for this flow, just return. This can happen // when fragments map to more than one flow, such as in the case of table @@ -2200,24 +2231,24 @@ impl BlockFlowDisplayListBuilding for BlockFlow { let content_rect = Rect::new(clip_origin, clip_size); preserved_state.push_clip(state, &content_rect, self.positioning()); - + let parent_id = self.scroll_root_id(state.layout_context.id); state.add_scroll_root( ScrollRoot { id: new_scroll_root_id, - parent_id: self.base.scroll_root_id, + parent_id: parent_id, clip: ClippingRegion::from_rect(&Rect::new(Point2D::zero(), clip_size)), content_rect: content_rect, }, self.base.stacking_context_id ); - self.base.scroll_root_id = new_scroll_root_id; + self.base.scroll_root_id = Some(new_scroll_root_id); state.current_scroll_root_id = new_scroll_root_id; } fn create_pseudo_stacking_context_for_block(&mut self, parent_stacking_context_id: StackingContextId, - parent_scroll_root_id: ScrollRootId, + parent_scroll_root_id: ClipId, state: &mut DisplayListBuildState) { let creation_mode = if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) || self.fragment.style.get_box().position != position::T::static_ { @@ -2251,7 +2282,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow { fn create_real_stacking_context_for_block(&mut self, parent_stacking_context_id: StackingContextId, - parent_scroll_root_id: ScrollRootId, + parent_scroll_root_id: ClipId, state: &mut DisplayListBuildState) { let scroll_policy = if self.is_fixed() { ScrollPolicy::Fixed @@ -2319,7 +2350,7 @@ pub trait InlineFlowDisplayListBuilding { impl InlineFlowDisplayListBuilding for InlineFlow { fn collect_stacking_contexts_for_inline(&mut self, state: &mut DisplayListBuildState) { self.base.stacking_context_id = state.current_stacking_context_id; - self.base.scroll_root_id = state.current_scroll_root_id; + self.base.scroll_root_id = Some(state.current_scroll_root_id); self.base.clip = state.clip_stack.last().cloned().unwrap_or_else(max_rect); for mut fragment in self.fragments.fragments.iter_mut() { @@ -2342,9 +2373,8 @@ impl InlineFlowDisplayListBuilding for InlineFlow { block_flow.collect_stacking_contexts(state); } _ if fragment.establishes_stacking_context() => { - fragment.stacking_context_id = - StackingContextId::new_of_type(fragment.fragment_id(), - fragment.fragment_type()); + fragment.stacking_context_id = fragment.stacking_context_id(); + let current_stacking_context_id = state.current_stacking_context_id; let current_scroll_root_id = state.current_scroll_root_id; state.add_stacking_context(current_stacking_context_id, @@ -2565,4 +2595,3 @@ pub enum StackingContextCreationMode { PseudoPositioned, PseudoFloat, } - diff --git a/servo/components/layout/flow.rs b/servo/components/layout/flow.rs index 372d76a404ca..a56cb7537d53 100644 --- a/servo/components/layout/flow.rs +++ b/servo/components/layout/flow.rs @@ -35,10 +35,11 @@ use floats::{Floats, SpeculatedFloatPlacement}; use flow_list::{FlowList, MutFlowListIterator}; use flow_ref::{FlowRef, WeakFlowRef}; use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, Overflow}; -use gfx_traits::{ScrollRootId, StackingContextId}; +use gfx_traits::StackingContextId; use gfx_traits::print_tree::PrintTree; use inline::InlineFlow; use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo}; +use msg::constellation_msg::PipelineId; use multicol::MulticolFlow; use parallel::FlowParallelInfo; use serde::ser::{Serialize, SerializeStruct, Serializer}; @@ -62,6 +63,7 @@ use table_colgroup::TableColGroupFlow; use table_row::TableRowFlow; use table_rowgroup::TableRowGroupFlow; use table_wrapper::TableWrapperFlow; +use webrender_traits::ClipId; /// Virtual methods that make up a float context. /// @@ -429,8 +431,14 @@ pub trait Flow: fmt::Debug + Sync + Send + 'static { /// children of this flow. fn print_extra_flow_children(&self, _: &mut PrintTree) { } - fn scroll_root_id(&self) -> ScrollRootId { - base(self).scroll_root_id + fn scroll_root_id(&self, pipeline_id: PipelineId) -> ClipId { + match base(self).scroll_root_id { + Some(id) => id, + None => { + warn!("Tried to access scroll root id on Flow before assignment"); + pipeline_id.root_scroll_node() + } + } } } @@ -961,7 +969,7 @@ pub struct BaseFlow { /// list construction. pub stacking_context_id: StackingContextId, - pub scroll_root_id: ScrollRootId, + pub scroll_root_id: Option, } impl fmt::Debug for BaseFlow { @@ -1104,8 +1112,8 @@ impl BaseFlow { flags: flags, writing_mode: writing_mode, thread_id: 0, - stacking_context_id: StackingContextId::new(0), - scroll_root_id: ScrollRootId::root(), + stacking_context_id: StackingContextId::root(), + scroll_root_id: None, } } diff --git a/servo/components/layout/fragment.rs b/servo/components/layout/fragment.rs index 420fb2c42ae1..ee892b75f112 100644 --- a/servo/components/layout/fragment.rs +++ b/servo/components/layout/fragment.rs @@ -17,7 +17,7 @@ use gfx; use gfx::display_list::{BLUR_INFLATION_FACTOR, OpaqueNode}; use gfx::text::glyph::ByteIndex; use gfx::text::text_run::{TextRun, TextRunSlice}; -use gfx_traits::{FragmentType, StackingContextId}; +use gfx_traits::StackingContextId; use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFragmentContext, InlineFragmentNodeInfo}; use inline::{InlineMetrics, LAST_FRAGMENT_OF_ELEMENT, LineMetrics}; use ipc_channel::ipc::IpcSender; @@ -665,7 +665,7 @@ impl Fragment { pseudo: node.get_pseudo_element_type().strip(), flags: FragmentFlags::empty(), debug_id: DebugId::new(), - stacking_context_id: StackingContextId::new(0), + stacking_context_id: StackingContextId::root(), } } @@ -694,7 +694,7 @@ impl Fragment { pseudo: pseudo, flags: FragmentFlags::empty(), debug_id: DebugId::new(), - stacking_context_id: StackingContextId::new(0), + stacking_context_id: StackingContextId::root(), } } @@ -719,7 +719,7 @@ impl Fragment { pseudo: self.pseudo, flags: FragmentFlags::empty(), debug_id: DebugId::new(), - stacking_context_id: StackingContextId::new(0), + stacking_context_id: StackingContextId::root(), } } @@ -747,7 +747,7 @@ impl Fragment { pseudo: self.pseudo.clone(), flags: FragmentFlags::empty(), debug_id: self.debug_id.clone(), - stacking_context_id: StackingContextId::new(0), + stacking_context_id: StackingContextId::root(), } } @@ -2798,21 +2798,6 @@ impl Fragment { } } - - pub fn fragment_id(&self) -> usize { - return self as *const Fragment as usize; - } - - pub fn fragment_type(&self) -> FragmentType { - match self.pseudo { - PseudoElementType::Normal => FragmentType::FragmentBody, - PseudoElementType::Before(_) => FragmentType::BeforePseudoContent, - PseudoElementType::After(_) => FragmentType::AfterPseudoContent, - PseudoElementType::DetailsSummary(_) => FragmentType::FragmentBody, - PseudoElementType::DetailsContent(_) => FragmentType::FragmentBody, - } - } - /// Returns true if any of the inline styles associated with this fragment have /// `vertical-align` set to `top` or `bottom`. pub fn is_vertically_aligned_to_top_or_bottom(&self) -> bool { diff --git a/servo/components/layout/query.rs b/servo/components/layout/query.rs index b4008d24c60f..88aca41ae30b 100644 --- a/servo/components/layout/query.rs +++ b/servo/components/layout/query.rs @@ -13,9 +13,9 @@ use euclid::size::Size2D; use flow::{self, Flow}; use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo}; use gfx::display_list::{DisplayItemMetadata, DisplayList, OpaqueNode, ScrollOffsetMap}; -use gfx_traits::ScrollRootId; use inline::LAST_FRAGMENT_OF_ELEMENT; use ipc_channel::ipc::IpcSender; +use msg::constellation_msg::PipelineId; use opaque_node::OpaqueNodeMethods; use script_layout_interface::PendingImage; use script_layout_interface::rpc::{ContentBoxResponse, ContentBoxesResponse}; @@ -41,6 +41,7 @@ use style::selector_parser::PseudoElement; use style::stylist::Stylist; use style_traits::ToCss; use style_traits::cursor::Cursor; +use webrender_traits::ClipId; use wrapper::{LayoutNodeHelpers, LayoutNodeLayoutData}; /// Mutable data belonging to the LayoutThread. @@ -69,7 +70,7 @@ pub struct LayoutThreadData { pub hit_test_response: (Option, bool), /// A queued response for the scroll root id for a given node. - pub scroll_root_id_response: Option, + pub scroll_root_id_response: Option, /// A pair of overflow property in x and y pub overflow_response: NodeOverflowResponse, @@ -650,9 +651,11 @@ pub fn process_node_geometry_request(requested_node: N, layout_ro iterator.client_rect } -pub fn process_node_scroll_root_id_request(requested_node: N) -> ScrollRootId { +pub fn process_node_scroll_root_id_request(id: PipelineId, + requested_node: N) + -> ClipId { let layout_node = requested_node.to_threadsafe(); - layout_node.scroll_root_id() + layout_node.generate_scroll_root_id(id) } pub fn process_node_scroll_area_request< N: LayoutNode>(requested_node: N, layout_root: &mut Flow) diff --git a/servo/components/layout/traversal.rs b/servo/components/layout/traversal.rs index 88852e4193a2..ab4f2c2f1b63 100644 --- a/servo/components/layout/traversal.rs +++ b/servo/components/layout/traversal.rs @@ -242,7 +242,7 @@ impl<'a> BuildDisplayList<'a> { self.state.current_stacking_context_id = flow::base(flow).stacking_context_id; let parent_scroll_root_id = self.state.current_scroll_root_id; - self.state.current_scroll_root_id = flow::base(flow).scroll_root_id; + self.state.current_scroll_root_id = flow.scroll_root_id(self.state.layout_context.id); if self.should_process() { flow.build_display_list(&mut self.state); diff --git a/servo/components/layout/webrender_helpers.rs b/servo/components/layout/webrender_helpers.rs index 0f21523ceb9d..9756ea6d1d68 100644 --- a/servo/components/layout/webrender_helpers.rs +++ b/servo/components/layout/webrender_helpers.rs @@ -11,7 +11,6 @@ use app_units::Au; use euclid::{Point2D, Rect, SideOffsets2D, Size2D}; use gfx::display_list::{BorderDetails, BorderRadii, BoxShadowClipMode, ClippingRegion}; use gfx::display_list::{DisplayItem, DisplayList, DisplayListTraversal, StackingContextType}; -use gfx_traits::ScrollRootId; use msg::constellation_msg::PipelineId; use style::computed_values::{image_rendering, mix_blend_mode}; use style::computed_values::filter::{self, Filter}; @@ -25,7 +24,7 @@ pub trait WebRenderDisplayListConverter { trait WebRenderDisplayItemConverter { fn convert_to_webrender(&self, builder: &mut DisplayListBuilder, - current_scroll_root_id: &mut ScrollRootId); + current_scroll_root_id: &mut ClipId); } trait ToBorderStyle { @@ -217,8 +216,8 @@ impl WebRenderDisplayListConverter for DisplayList { let webrender_pipeline_id = pipeline_id.to_webrender(); let mut builder = DisplayListBuilder::new(webrender_pipeline_id); - let mut current_scroll_root_id = ScrollRootId::root(); - builder.push_clip_id(current_scroll_root_id.convert_to_webrender(webrender_pipeline_id)); + let mut current_scroll_root_id = ClipId::root_scroll_node(webrender_pipeline_id); + builder.push_clip_id(current_scroll_root_id); for item in traversal { item.convert_to_webrender(&mut builder, &mut current_scroll_root_id); @@ -230,12 +229,11 @@ impl WebRenderDisplayListConverter for DisplayList { impl WebRenderDisplayItemConverter for DisplayItem { fn convert_to_webrender(&self, builder: &mut DisplayListBuilder, - current_scroll_root_id: &mut ScrollRootId) { + current_scroll_root_id: &mut ClipId) { let scroll_root_id = self.base().scroll_root_id; if scroll_root_id != *current_scroll_root_id { - let pipeline_id = builder.pipeline_id; builder.pop_clip_id(); - builder.push_clip_id(scroll_root_id.convert_to_webrender(pipeline_id)); + builder.push_clip_id(scroll_root_id); *current_scroll_root_id = scroll_root_id; } @@ -425,10 +423,9 @@ impl WebRenderDisplayItemConverter for DisplayItem { } DisplayItem::PopStackingContext(_) => builder.pop_stacking_context(), DisplayItem::PushScrollRoot(ref item) => { - let pipeline_id = builder.pipeline_id; - builder.push_clip_id(item.scroll_root.parent_id.convert_to_webrender(pipeline_id)); + builder.push_clip_id(item.scroll_root.parent_id); - let our_id = item.scroll_root.id.convert_to_webrender(pipeline_id); + let our_id = item.scroll_root.id; let clip = item.scroll_root.clip.to_clip_region(builder); let content_rect = item.scroll_root.content_rect.to_rectf(); let webrender_id = builder.define_clip(content_rect, clip, Some(our_id)); @@ -440,16 +437,3 @@ impl WebRenderDisplayItemConverter for DisplayItem { } } } -trait WebRenderScrollRootIdConverter { - fn convert_to_webrender(&self, pipeline_id: webrender_traits::PipelineId) -> ClipId; -} - -impl WebRenderScrollRootIdConverter for ScrollRootId { - fn convert_to_webrender(&self, pipeline_id: webrender_traits::PipelineId) -> ClipId { - if *self == ScrollRootId::root() { - ClipId::root_scroll_node(pipeline_id) - } else { - ClipId::new(self.0 as u64, pipeline_id) - } - } -} diff --git a/servo/components/layout_thread/lib.rs b/servo/components/layout_thread/lib.rs index 286d49484f6d..fe6e6d0dea20 100644 --- a/servo/components/layout_thread/lib.rs +++ b/servo/components/layout_thread/lib.rs @@ -49,7 +49,7 @@ use gfx::display_list::{OpaqueNode, WebRenderImageInfo}; use gfx::font; use gfx::font_cache_thread::FontCacheThread; use gfx::font_context; -use gfx_traits::{Epoch, FragmentType, ScrollRootId}; +use gfx_traits::{Epoch, node_id_from_clip_id}; use heapsize::HeapSizeOf; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::router::ROUTER; @@ -514,6 +514,7 @@ impl LayoutThread { ThreadLocalStyleContextCreationInfo::new(self.new_animations_sender.clone()); LayoutContext { + id: self.id, style_context: SharedStyleContext { stylist: rw_data.stylist.clone(), options: StyleSystemOptions::default(), @@ -1282,7 +1283,8 @@ impl LayoutThread { }, ReflowQueryType::NodeScrollRootIdQuery(node) => { let node = unsafe { ServoLayoutNode::new(&node) }; - rw_data.scroll_root_id_response = Some(process_node_scroll_root_id_request(node)); + rw_data.scroll_root_id_response = Some(process_node_scroll_root_id_request(self.id, + node)); }, ReflowQueryType::ResolvedStyleQuery(node, ref pseudo, ref property) => { let node = unsafe { ServoLayoutNode::new(&node) }; @@ -1339,12 +1341,12 @@ impl LayoutThread { let offset = new_scroll_state.scroll_offset; layout_scroll_states.insert(new_scroll_state.scroll_root_id, offset); - if new_scroll_state.scroll_root_id == ScrollRootId::root() { + if new_scroll_state.scroll_root_id.is_root_scroll_node() { script_scroll_states.push((UntrustedNodeAddress::from_id(0), offset)) - } else if !new_scroll_state.scroll_root_id.is_special() && - new_scroll_state.scroll_root_id.fragment_type() == FragmentType::FragmentBody { - let id = new_scroll_state.scroll_root_id.id(); - script_scroll_states.push((UntrustedNodeAddress::from_id(id), offset)) + } else if let Some(id) = new_scroll_state.scroll_root_id.external_id() { + if let Some(node_id) = node_id_from_clip_id(id as usize) { + script_scroll_states.push((UntrustedNodeAddress::from_id(node_id), offset)) + } } } let _ = self.script_chan diff --git a/servo/components/msg/constellation_msg.rs b/servo/components/msg/constellation_msg.rs index dddfb0c00422..5b5110099f67 100644 --- a/servo/components/msg/constellation_msg.rs +++ b/servo/components/msg/constellation_msg.rs @@ -244,6 +244,10 @@ impl PipelineId { let PipelineIndex(index) = self.index; webrender_traits::PipelineId(namespace_id, index) } + + pub fn root_scroll_node(&self) -> webrender_traits::ClipId { + webrender_traits::ClipId::root_scroll_node(self.to_webrender()) + } } impl fmt::Display for PipelineId { diff --git a/servo/components/script/dom/document.rs b/servo/components/script/dom/document.rs index 425336fd669c..f5ffd9739364 100644 --- a/servo/components/script/dom/document.rs +++ b/servo/components/script/dom/document.rs @@ -93,7 +93,6 @@ use dom_struct::dom_struct; use encoding::EncodingRef; use encoding::all::UTF_8; use euclid::point::Point2D; -use gfx_traits::ScrollRootId; use html5ever_atoms::{LocalName, QualName}; use hyper::header::{Header, SetCookie}; use hyper_serde::Serde; @@ -143,6 +142,7 @@ use time; use timers::OneshotTimerCallback; use url::Host; use url::percent_encoding::percent_decode; +use webrender_traits::ClipId; /// The number of times we are allowed to see spurious `requestAnimationFrame()` calls before /// falling back to fake ones. @@ -699,9 +699,11 @@ impl Document { if let Some((x, y)) = point { // Step 3 + let global_scope = self.window.upcast::(); + let webrender_pipeline_id = global_scope.pipeline_id().to_webrender(); self.window.perform_a_scroll(x, y, - ScrollRootId::root(), + ClipId::root_scroll_node(webrender_pipeline_id), ScrollBehavior::Instant, target.r()); } diff --git a/servo/components/script/dom/window.rs b/servo/components/script/dom/window.rs index 0c8ea1a6594b..df7fe995c1fd 100644 --- a/servo/components/script/dom/window.rs +++ b/servo/components/script/dom/window.rs @@ -52,7 +52,6 @@ use dom::testrunner::TestRunner; use dom_struct::dom_struct; use euclid::{Point2D, Rect, Size2D}; use fetch; -use gfx_traits::ScrollRootId; use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::router::ROUTER; use js::jsapi::{HandleObject, HandleValue, JSAutoCompartment, JSContext}; @@ -122,6 +121,7 @@ use timers::{IsInterval, TimerCallback}; use tinyfiledialogs::{self, MessageBoxIcon}; use url::Position; use webdriver_handlers::jsval_to_webdriver; +use webrender_traits::ClipId; use webvr_traits::WebVRMsg; /// Current state of the window object @@ -1077,9 +1077,10 @@ impl Window { //TODO Step 11 //let document = self.Document(); // Step 12 + let global_scope = self.upcast::(); self.perform_a_scroll(x.to_f32().unwrap_or(0.0f32), y.to_f32().unwrap_or(0.0f32), - ScrollRootId::root(), + global_scope.pipeline_id().root_scroll_node(), behavior, None); } @@ -1088,7 +1089,7 @@ impl Window { pub fn perform_a_scroll(&self, x: f32, y: f32, - scroll_root_id: ScrollRootId, + scroll_root_id: ClipId, behavior: ScrollBehavior, element: Option<&Element>) { //TODO Step 1 @@ -1108,8 +1109,7 @@ impl Window { self.update_viewport_for_scroll(x, y); let global_scope = self.upcast::(); - let message = ConstellationMsg::ScrollFragmentPoint( - global_scope.pipeline_id(), scroll_root_id, point, smooth); + let message = ConstellationMsg::ScrollFragmentPoint(scroll_root_id, point, smooth); global_scope.constellation_chan().send(message).unwrap(); } diff --git a/servo/components/script_layout_interface/Cargo.toml b/servo/components/script_layout_interface/Cargo.toml index 62fd1dc21361..9db6a37eea02 100644 --- a/servo/components/script_layout_interface/Cargo.toml +++ b/servo/components/script_layout_interface/Cargo.toml @@ -30,3 +30,4 @@ script_traits = {path = "../script_traits"} selectors = { path = "../selectors" } servo_url = {path = "../url"} style = {path = "../style"} +webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]} diff --git a/servo/components/script_layout_interface/lib.rs b/servo/components/script_layout_interface/lib.rs index 674b5325e812..98375e6a05a1 100644 --- a/servo/components/script_layout_interface/lib.rs +++ b/servo/components/script_layout_interface/lib.rs @@ -32,6 +32,7 @@ extern crate script_traits; extern crate selectors; extern crate servo_url; extern crate style; +extern crate webrender_traits; pub mod message; pub mod reporter; diff --git a/servo/components/script_layout_interface/rpc.rs b/servo/components/script_layout_interface/rpc.rs index b07fa25a8c12..82dd9b9ff084 100644 --- a/servo/components/script_layout_interface/rpc.rs +++ b/servo/components/script_layout_interface/rpc.rs @@ -6,9 +6,9 @@ use PendingImage; use app_units::Au; use euclid::point::Point2D; use euclid::rect::Rect; -use gfx_traits::ScrollRootId; use script_traits::UntrustedNodeAddress; use style::properties::longhands::{margin_top, margin_right, margin_bottom, margin_left, overflow_x}; +use webrender_traits::ClipId; /// Synchronous messages that script can send to layout. /// @@ -56,7 +56,7 @@ pub struct NodeGeometryResponse { pub struct NodeOverflowResponse(pub Option>); -pub struct NodeScrollRootIdResponse(pub ScrollRootId); +pub struct NodeScrollRootIdResponse(pub ClipId); pub struct HitTestResponse { pub node_address: Option, diff --git a/servo/components/script_layout_interface/wrapper_traits.rs b/servo/components/script_layout_interface/wrapper_traits.rs index 88a1dbebb33c..4abc74bcac0c 100644 --- a/servo/components/script_layout_interface/wrapper_traits.rs +++ b/servo/components/script_layout_interface/wrapper_traits.rs @@ -9,7 +9,7 @@ use LayoutNodeType; use OpaqueStyleAndLayoutData; use SVGSVGData; use atomic_refcell::AtomicRefCell; -use gfx_traits::{ByteIndex, FragmentType, ScrollRootId}; +use gfx_traits::{ByteIndex, FragmentType, combine_id_with_fragment_type}; use html5ever_atoms::{Namespace, LocalName}; use msg::constellation_msg::PipelineId; use range::Range; @@ -24,6 +24,7 @@ use style::dom::OpaqueNode; use style::font_metrics::ServoMetricsProvider; use style::properties::{CascadeFlags, ServoComputedValues}; use style::selector_parser::{PseudoElement, PseudoElementCascadeType, SelectorImpl}; +use webrender_traits::ClipId; #[derive(Copy, PartialEq, Clone, Debug)] pub enum PseudoElementType { @@ -288,8 +289,9 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + Debug + GetLayoutData + NodeInfo } } - fn scroll_root_id(&self) -> ScrollRootId { - ScrollRootId::new_of_type(self.opaque().id() as usize, self.fragment_type()) + fn generate_scroll_root_id(&self, pipeline_id: PipelineId) -> ClipId { + let id = combine_id_with_fragment_type(self.opaque().id(), self.fragment_type()); + ClipId::new(id as u64, pipeline_id.to_webrender()) } } diff --git a/servo/components/script_traits/Cargo.toml b/servo/components/script_traits/Cargo.toml index c33320461179..da5fcc78704d 100644 --- a/servo/components/script_traits/Cargo.toml +++ b/servo/components/script_traits/Cargo.toml @@ -34,4 +34,5 @@ servo_url = {path = "../url"} style_traits = {path = "../style_traits", features = ["servo"]} time = "0.1.12" url = {version = "1.2", features = ["heap_size"]} +webrender_traits = {git = "https://github.com/servo/webrender", features = ["ipc"]} webvr_traits = {path = "../webvr_traits"} diff --git a/servo/components/script_traits/lib.rs b/servo/components/script_traits/lib.rs index f7248466d391..da5191f73bdc 100644 --- a/servo/components/script_traits/lib.rs +++ b/servo/components/script_traits/lib.rs @@ -33,6 +33,7 @@ extern crate serde_derive; extern crate servo_url; extern crate style_traits; extern crate time; +extern crate webrender_traits; extern crate webvr_traits; mod script_msg; @@ -47,7 +48,6 @@ use euclid::rect::Rect; use euclid::scale_factor::ScaleFactor; use euclid::size::TypedSize2D; use gfx_traits::Epoch; -use gfx_traits::ScrollRootId; use heapsize::HeapSizeOf; use hyper::header::Headers; use hyper::method::Method; @@ -71,6 +71,7 @@ use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender}; use style_traits::{CSSPixel, UnsafeNode}; use webdriver_msg::{LoadStatus, WebDriverScriptCommand}; +use webrender_traits::ClipId; use webvr_traits::{WebVREvent, WebVRMsg}; pub use script_msg::{LayoutMsg, ScriptMsg, EventResult, LogEntry}; @@ -662,7 +663,7 @@ pub enum AnimationTickType { #[derive(Copy, Clone, Debug, Deserialize, Serialize)] pub struct StackingContextScrollState { /// The ID of the scroll root. - pub scroll_root_id: ScrollRootId, + pub scroll_root_id: ClipId, /// The scrolling offset of this stacking context. pub scroll_offset: Point2D, } diff --git a/servo/components/script_traits/script_msg.rs b/servo/components/script_traits/script_msg.rs index 3e61fa8ae62b..47a7b103c8cc 100644 --- a/servo/components/script_traits/script_msg.rs +++ b/servo/components/script_traits/script_msg.rs @@ -16,7 +16,6 @@ use canvas_traits::CanvasMsg; use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId}; use euclid::point::Point2D; use euclid::size::{Size2D, TypedSize2D}; -use gfx_traits::ScrollRootId; use ipc_channel::ipc::IpcSender; use msg::constellation_msg::{FrameId, FrameType, PipelineId, TraversalDirection}; use msg::constellation_msg::{Key, KeyModifiers, KeyState}; @@ -28,6 +27,7 @@ use servo_url::ServoUrl; use style_traits::CSSPixel; use style_traits::cursor::Cursor; use style_traits::viewport::ViewportConstraints; +use webrender_traits::ClipId; /// Messages from the layout to the constellation. #[derive(Deserialize, Serialize)] @@ -133,7 +133,7 @@ pub enum ScriptMsg { /// Check if an alert dialog box should be presented Alert(PipelineId, String, IpcSender), /// Scroll a page in a window - ScrollFragmentPoint(PipelineId, ScrollRootId, Point2D, bool), + ScrollFragmentPoint(ClipId, Point2D, bool), /// Set title of current page /// https://html.spec.whatwg.org/multipage/#document.title SetTitle(PipelineId, Option), From 752d7c7482ebff40fc53cc828a795ec53f16240b Mon Sep 17 00:00:00 2001 From: Marco Bonardo Date: Tue, 18 Apr 2017 23:51:05 +0200 Subject: [PATCH 28/65] Bug 1357555 - Properly handle an expiration value of 0 when fetching an icon. r=adw Favicons migrated from the old store have expiration set to 0. The code is not expecting that, since expiration has always been positive, thus those icons are always considered valid and never replaced. They should instead be considered expired. MozReview-Commit-ID: Cz0JB4IbURA --HG-- extra : rebase_source : c9676529bd73581f3325c8a267c8863ff09767a3 --- toolkit/components/places/FaviconHelpers.cpp | 4 +-- .../favicons/test_expire_migrated_icons.js | 27 +++++++++++++++++++ .../places/tests/favicons/xpcshell.ini | 1 + .../components/places/tests/head_common.js | 6 +++-- 4 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 toolkit/components/places/tests/favicons/test_expire_migrated_icons.js diff --git a/toolkit/components/places/FaviconHelpers.cpp b/toolkit/components/places/FaviconHelpers.cpp index 52947c58305d..e93549bbde63 100644 --- a/toolkit/components/places/FaviconHelpers.cpp +++ b/toolkit/components/places/FaviconHelpers.cpp @@ -159,6 +159,7 @@ SetIconInfo(const RefPtr& aDB, MOZ_ASSERT(!NS_IsMainThread()); MOZ_ASSERT(aIcon.payloads.Length() > 0); MOZ_ASSERT(!aIcon.spec.IsEmpty()); + MOZ_ASSERT(aIcon.expiration > 0); // There are multiple cases possible at this point: // 1. We must insert some payloads and no payloads exist in the table. This @@ -519,8 +520,7 @@ AsyncFetchAndSetIconForPage::Run() nsresult rv = FetchIconInfo(DB, 0, mIcon); NS_ENSURE_SUCCESS(rv, rv); - bool isInvalidIcon = !mIcon.payloads.Length() || - (mIcon.expiration && PR_Now() > mIcon.expiration); + bool isInvalidIcon = !mIcon.payloads.Length() || PR_Now() > mIcon.expiration; bool fetchIconFromNetwork = mIcon.fetchMode == FETCH_ALWAYS || (mIcon.fetchMode == FETCH_IF_MISSING && isInvalidIcon); diff --git a/toolkit/components/places/tests/favicons/test_expire_migrated_icons.js b/toolkit/components/places/tests/favicons/test_expire_migrated_icons.js new file mode 100644 index 000000000000..25185cd9cfc2 --- /dev/null +++ b/toolkit/components/places/tests/favicons/test_expire_migrated_icons.js @@ -0,0 +1,27 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * This file tests that favicons migrated from a previous profile, having a 0 + * expiration, will be properly expired when fetching new ones. + */ + +add_task(function* test_storing_a_normal_16x16_icon() { + const PAGE_URL = "http://places.test"; + yield PlacesTestUtils.addVisits(PAGE_URL); + yield setFaviconForPage(PAGE_URL, SMALLPNG_DATA_URI); + + // Now set expiration to 0 and change the payload. + do_print("Set expiration to 0 and replace favicon data"); + yield PlacesUtils.withConnectionWrapper("Change favicons payload", db => { + return db.execute(`UPDATE moz_icons SET expire_ms = 0, data = "test"`); + }); + + let {data, mimeType} = yield getFaviconDataForPage(PAGE_URL); + Assert.equal(mimeType, "image/png"); + Assert.deepEqual(data, "test".split('').map(c => c.charCodeAt(0))); + + do_print("Refresh favicon"); + yield setFaviconForPage(PAGE_URL, SMALLPNG_DATA_URI, false); + yield compareFavicons("page-icon:" + PAGE_URL, SMALLPNG_DATA_URI); +}); diff --git a/toolkit/components/places/tests/favicons/xpcshell.ini b/toolkit/components/places/tests/favicons/xpcshell.ini index a60ca0bc6822..38442056db23 100644 --- a/toolkit/components/places/tests/favicons/xpcshell.ini +++ b/toolkit/components/places/tests/favicons/xpcshell.ini @@ -24,6 +24,7 @@ support-files = favicon-scale3x160.jpg [test_expireAllFavicons.js] +[test_expire_migrated_icons.js] [test_expire_on_new_icons.js] [test_favicons_conversions.js] [test_favicons_protocols_ref.js] diff --git a/toolkit/components/places/tests/head_common.js b/toolkit/components/places/tests/head_common.js index ac7fe3ed3074..452c11acb511 100644 --- a/toolkit/components/places/tests/head_common.js +++ b/toolkit/components/places/tests/head_common.js @@ -863,15 +863,17 @@ function sortBy(array, prop) { * The page's URL * @param icon * The URL of the favicon to be set. + * @param [optional] forceReload + * Whether to enforce reloading the icon. */ -function setFaviconForPage(page, icon) { +function setFaviconForPage(page, icon, forceReload = true) { let pageURI = page instanceof Ci.nsIURI ? page : NetUtil.newURI(new URL(page).href); let iconURI = icon instanceof Ci.nsIURI ? icon : NetUtil.newURI(new URL(icon).href); return new Promise(resolve => { PlacesUtils.favicons.setAndFetchFaviconForPage( - pageURI, iconURI, true, + pageURI, iconURI, forceReload, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, resolve, Services.scriptSecurityManager.getSystemPrincipal() From 9a405f840513d3afb3d8ab5403e9ed0daac31f41 Mon Sep 17 00:00:00 2001 From: Iris Hsiao Date: Thu, 20 Apr 2017 16:23:59 +0800 Subject: [PATCH 29/65] Backed out changeset 3507329c5999 (bug 1357555o) for eslint failure in test_expire_migrated_icons.js --- toolkit/components/places/FaviconHelpers.cpp | 4 +-- .../favicons/test_expire_migrated_icons.js | 27 ------------------- .../places/tests/favicons/xpcshell.ini | 1 - .../components/places/tests/head_common.js | 6 ++--- 4 files changed, 4 insertions(+), 34 deletions(-) delete mode 100644 toolkit/components/places/tests/favicons/test_expire_migrated_icons.js diff --git a/toolkit/components/places/FaviconHelpers.cpp b/toolkit/components/places/FaviconHelpers.cpp index e93549bbde63..52947c58305d 100644 --- a/toolkit/components/places/FaviconHelpers.cpp +++ b/toolkit/components/places/FaviconHelpers.cpp @@ -159,7 +159,6 @@ SetIconInfo(const RefPtr& aDB, MOZ_ASSERT(!NS_IsMainThread()); MOZ_ASSERT(aIcon.payloads.Length() > 0); MOZ_ASSERT(!aIcon.spec.IsEmpty()); - MOZ_ASSERT(aIcon.expiration > 0); // There are multiple cases possible at this point: // 1. We must insert some payloads and no payloads exist in the table. This @@ -520,7 +519,8 @@ AsyncFetchAndSetIconForPage::Run() nsresult rv = FetchIconInfo(DB, 0, mIcon); NS_ENSURE_SUCCESS(rv, rv); - bool isInvalidIcon = !mIcon.payloads.Length() || PR_Now() > mIcon.expiration; + bool isInvalidIcon = !mIcon.payloads.Length() || + (mIcon.expiration && PR_Now() > mIcon.expiration); bool fetchIconFromNetwork = mIcon.fetchMode == FETCH_ALWAYS || (mIcon.fetchMode == FETCH_IF_MISSING && isInvalidIcon); diff --git a/toolkit/components/places/tests/favicons/test_expire_migrated_icons.js b/toolkit/components/places/tests/favicons/test_expire_migrated_icons.js deleted file mode 100644 index 25185cd9cfc2..000000000000 --- a/toolkit/components/places/tests/favicons/test_expire_migrated_icons.js +++ /dev/null @@ -1,27 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -/** - * This file tests that favicons migrated from a previous profile, having a 0 - * expiration, will be properly expired when fetching new ones. - */ - -add_task(function* test_storing_a_normal_16x16_icon() { - const PAGE_URL = "http://places.test"; - yield PlacesTestUtils.addVisits(PAGE_URL); - yield setFaviconForPage(PAGE_URL, SMALLPNG_DATA_URI); - - // Now set expiration to 0 and change the payload. - do_print("Set expiration to 0 and replace favicon data"); - yield PlacesUtils.withConnectionWrapper("Change favicons payload", db => { - return db.execute(`UPDATE moz_icons SET expire_ms = 0, data = "test"`); - }); - - let {data, mimeType} = yield getFaviconDataForPage(PAGE_URL); - Assert.equal(mimeType, "image/png"); - Assert.deepEqual(data, "test".split('').map(c => c.charCodeAt(0))); - - do_print("Refresh favicon"); - yield setFaviconForPage(PAGE_URL, SMALLPNG_DATA_URI, false); - yield compareFavicons("page-icon:" + PAGE_URL, SMALLPNG_DATA_URI); -}); diff --git a/toolkit/components/places/tests/favicons/xpcshell.ini b/toolkit/components/places/tests/favicons/xpcshell.ini index 38442056db23..a60ca0bc6822 100644 --- a/toolkit/components/places/tests/favicons/xpcshell.ini +++ b/toolkit/components/places/tests/favicons/xpcshell.ini @@ -24,7 +24,6 @@ support-files = favicon-scale3x160.jpg [test_expireAllFavicons.js] -[test_expire_migrated_icons.js] [test_expire_on_new_icons.js] [test_favicons_conversions.js] [test_favicons_protocols_ref.js] diff --git a/toolkit/components/places/tests/head_common.js b/toolkit/components/places/tests/head_common.js index 452c11acb511..ac7fe3ed3074 100644 --- a/toolkit/components/places/tests/head_common.js +++ b/toolkit/components/places/tests/head_common.js @@ -863,17 +863,15 @@ function sortBy(array, prop) { * The page's URL * @param icon * The URL of the favicon to be set. - * @param [optional] forceReload - * Whether to enforce reloading the icon. */ -function setFaviconForPage(page, icon, forceReload = true) { +function setFaviconForPage(page, icon) { let pageURI = page instanceof Ci.nsIURI ? page : NetUtil.newURI(new URL(page).href); let iconURI = icon instanceof Ci.nsIURI ? icon : NetUtil.newURI(new URL(icon).href); return new Promise(resolve => { PlacesUtils.favicons.setAndFetchFaviconForPage( - pageURI, iconURI, forceReload, + pageURI, iconURI, true, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, resolve, Services.scriptSecurityManager.getSystemPrincipal() From 8a220bcecdabfed10c0bff87b1cebae4e1e79c37 Mon Sep 17 00:00:00 2001 From: Frank Serrano Date: Wed, 19 Apr 2017 21:02:17 -0500 Subject: [PATCH 30/65] Bug 1357832 - Update eula.css to use standard css border; r=dao We were using -moz-border-*-colors in eula.css before. We no longer need to do that, so we are changing it to use the standard css border MozReview-Commit-ID: KvJ0kigreEt --HG-- extra : rebase_source : d6ff70b0b425ef3a900e65c3431027e57674ced3 --- toolkit/themes/osx/mozapps/extensions/eula.css | 6 +----- toolkit/themes/windows/mozapps/extensions/eula.css | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/toolkit/themes/osx/mozapps/extensions/eula.css b/toolkit/themes/osx/mozapps/extensions/eula.css index 05aeb3c1c487..c12803486b7d 100644 --- a/toolkit/themes/osx/mozapps/extensions/eula.css +++ b/toolkit/themes/osx/mozapps/extensions/eula.css @@ -38,10 +38,6 @@ color: -moz-FieldText; background-color: -moz-Field; margin: 1em; - border: 1px solid; - -moz-border-top-colors: ActiveBorder; - -moz-border-right-colors: ActiveBorder; - -moz-border-bottom-colors: ActiveBorder; - -moz-border-left-colors: ActiveBorder; + border: 1px solid ActiveBorder; } diff --git a/toolkit/themes/windows/mozapps/extensions/eula.css b/toolkit/themes/windows/mozapps/extensions/eula.css index 05aeb3c1c487..c12803486b7d 100644 --- a/toolkit/themes/windows/mozapps/extensions/eula.css +++ b/toolkit/themes/windows/mozapps/extensions/eula.css @@ -38,10 +38,6 @@ color: -moz-FieldText; background-color: -moz-Field; margin: 1em; - border: 1px solid; - -moz-border-top-colors: ActiveBorder; - -moz-border-right-colors: ActiveBorder; - -moz-border-bottom-colors: ActiveBorder; - -moz-border-left-colors: ActiveBorder; + border: 1px solid ActiveBorder; } From 065b13fe5296cc0e018d49d9e9679b07cd184ac0 Mon Sep 17 00:00:00 2001 From: Daosheng Mu Date: Tue, 18 Apr 2017 12:45:44 +0800 Subject: [PATCH 31/65] Bug 1356452 - Part 1: Remove assertion for checking VRManager::Get(); r=kip MozReview-Commit-ID: CMCX9Fq55tS --HG-- extra : rebase_source : 10342128d91fea22b66dfd99379764ac6cccccc4 --- gfx/vr/gfxVR.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/gfx/vr/gfxVR.cpp b/gfx/vr/gfxVR.cpp index 29e8f23a338d..1d97d5214fe5 100644 --- a/gfx/vr/gfxVR.cpp +++ b/gfx/vr/gfxVR.cpp @@ -71,7 +71,6 @@ VRSystemManager::AddGamepad(const VRControllerInfo& controllerInfo) controllerInfo.GetNumHaptics()); VRManager* vm = VRManager::Get(); - MOZ_ASSERT(vm); vm->NotifyGamepadChange(a); } @@ -81,7 +80,6 @@ VRSystemManager::RemoveGamepad(uint32_t aIndex) dom::GamepadRemoved a(aIndex, dom::GamepadServiceType::VR); VRManager* vm = VRManager::Get(); - MOZ_ASSERT(vm); vm->NotifyGamepadChange(a); } @@ -93,7 +91,6 @@ VRSystemManager::NewButtonEvent(uint32_t aIndex, uint32_t aButton, aButton, aValue, aPressed, aTouched); VRManager* vm = VRManager::Get(); - MOZ_ASSERT(vm); vm->NotifyGamepadChange(a); } @@ -105,7 +102,6 @@ VRSystemManager::NewAxisMove(uint32_t aIndex, uint32_t aAxis, aAxis, aValue); VRManager* vm = VRManager::Get(); - MOZ_ASSERT(vm); vm->NotifyGamepadChange(a); } @@ -117,6 +113,5 @@ VRSystemManager::NewPoseState(uint32_t aIndex, aPose); VRManager* vm = VRManager::Get(); - MOZ_ASSERT(vm); vm->NotifyGamepadChange(a); } From ba21000af3db02f0fd21c7183942e41922aa1882 Mon Sep 17 00:00:00 2001 From: Daosheng Mu Date: Tue, 18 Apr 2017 13:04:53 +0800 Subject: [PATCH 32/65] Bug 1356452 - Part 2: Replace vr:: namespace with ::vr:: in OpenVR; r=kip MozReview-Commit-ID: uBvQ7hBI4z --HG-- extra : rebase_source : 306dc8eb907f0d33aa62ec05f3fe97d1f07ffc69 --- gfx/vr/gfxVROpenVR.cpp | 102 +++++++++++++++++++---------------------- gfx/vr/gfxVROpenVR.h | 12 +++-- 2 files changed, 53 insertions(+), 61 deletions(-) diff --git a/gfx/vr/gfxVROpenVR.cpp b/gfx/vr/gfxVROpenVR.cpp index 3569724a532d..c595b4d44861 100644 --- a/gfx/vr/gfxVROpenVR.cpp +++ b/gfx/vr/gfxVROpenVR.cpp @@ -40,7 +40,7 @@ using namespace mozilla::layers; using namespace mozilla::dom; #define BTN_MASK_FROM_ID(_id) \ - vr::ButtonMaskFromId(vr::EVRButtonId::_id) + ::vr::ButtonMaskFromId(vr::EVRButtonId::_id) static const uint32_t kNumOpenVRHaptcs = 1; @@ -342,7 +342,7 @@ VRDisplayOpenVR::NotifyVSync() } VRControllerOpenVR::VRControllerOpenVR(dom::GamepadHand aHand, uint32_t aNumButtons, - uint32_t aNumAxes, vr::ETrackedDeviceClass aDeviceType) + uint32_t aNumAxes, ::vr::ETrackedDeviceClass aDeviceType) : VRControllerHost(VRDeviceType::OpenVR) , mTrigger(0) , mVibrateThread(nullptr) @@ -351,10 +351,10 @@ VRControllerOpenVR::VRControllerOpenVR(dom::GamepadHand aHand, uint32_t aNumButt MOZ_COUNT_CTOR_INHERITED(VRControllerOpenVR, VRControllerHost); switch (aDeviceType) { - case vr::TrackedDeviceClass_Controller: + case ::vr::TrackedDeviceClass_Controller: mControllerInfo.mControllerName.AssignLiteral("OpenVR Gamepad"); break; - case vr::TrackedDeviceClass_GenericTracker: + case ::vr::TrackedDeviceClass_GenericTracker: mControllerInfo.mControllerName.AssignLiteral("OpenVR Tracker"); break; default: @@ -404,7 +404,8 @@ VRControllerOpenVR::GetTrigger() } void -VRControllerOpenVR::UpdateVibrateHaptic(vr::IVRSystem* aVRSystem, +void +VRControllerOpenVR::UpdateVibrateHaptic(::vr::IVRSystem* aVRSystem, uint32_t aHapticIndex, double aIntensity, double aDuration, @@ -440,7 +441,7 @@ VRControllerOpenVR::UpdateVibrateHaptic(vr::IVRSystem* aVRSystem, MOZ_ASSERT(mVibrateThread); RefPtr runnable = - NewRunnableMethod + NewRunnableMethod<::vr::IVRSystem*, uint32_t, double, double, uint64_t, uint32_t> (this, &VRControllerOpenVR::UpdateVibrateHaptic, aVRSystem, aHapticIndex, aIntensity, duration - kVibrateRate, aVibrateIndex, aPromiseID); NS_DelayedDispatchToCurrentThread(runnable.forget(), kVibrateRate); @@ -461,7 +462,7 @@ VRControllerOpenVR::VibrateHapticComplete(uint32_t aPromiseID) } void -VRControllerOpenVR::VibrateHaptic(vr::IVRSystem* aVRSystem, +VRControllerOpenVR::VibrateHaptic(::vr::IVRSystem* aVRSystem, uint32_t aHapticIndex, double aIntensity, double aDuration, @@ -480,7 +481,7 @@ VRControllerOpenVR::VibrateHaptic(vr::IVRSystem* aVRSystem, mIsVibrateStopped = false; RefPtr runnable = - NewRunnableMethod + NewRunnableMethod<::vr::IVRSystem*, uint32_t, double, double, uint64_t, uint32_t> (this, &VRControllerOpenVR::UpdateVibrateHaptic, aVRSystem, aHapticIndex, aIntensity, aDuration, mVibrateIndex, aPromiseID); mVibrateThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL); @@ -591,10 +592,10 @@ VRSystemManagerOpenVR::HandleInput() } RefPtr controller; - vr::VRControllerState_t state; - vr::TrackedDevicePose_t poses[vr::k_unMaxTrackedDeviceCount]; - mVRSystem->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseSeated, 0.0f, - poses, vr::k_unMaxTrackedDeviceCount); + ::vr::VRControllerState_t state; + ::vr::TrackedDevicePose_t poses[::vr::k_unMaxTrackedDeviceCount]; + mVRSystem->GetDeviceToAbsoluteTrackingPose(::vr::TrackingUniverseSeated, 0.0f, + poses, ::vr::k_unMaxTrackedDeviceCount); // Process OpenVR controller state for (uint32_t i = 0; i < mOpenVRController.Length(); ++i) { uint32_t axisIdx = 0; @@ -603,19 +604,19 @@ VRSystemManagerOpenVR::HandleInput() const uint32_t trackedIndex = controller->GetTrackedIndex(); MOZ_ASSERT(mVRSystem->GetTrackedDeviceClass(trackedIndex) - == vr::TrackedDeviceClass_Controller || + == ::vr::TrackedDeviceClass_Controller || mVRSystem->GetTrackedDeviceClass(trackedIndex) - == vr::TrackedDeviceClass_GenericTracker); + == ::vr::TrackedDeviceClass_GenericTracker); if (mVRSystem->GetControllerState(trackedIndex, &state, sizeof(state))) { - for (uint32_t j = 0; j < vr::k_unControllerStateAxisCount; ++j) { + for (uint32_t j = 0; j < ::vr::k_unControllerStateAxisCount; ++j) { const uint32_t axisType = mVRSystem->GetInt32TrackedDeviceProperty( trackedIndex, - static_cast( - vr::Prop_Axis0Type_Int32 + j)); + static_cast<::vr::TrackedDeviceProperty>( + ::vr::Prop_Axis0Type_Int32 + j)); switch (axisType) { - case vr::EVRControllerAxisType::k_eControllerAxis_Joystick: - case vr::EVRControllerAxisType::k_eControllerAxis_TrackPad: + case ::vr::EVRControllerAxisType::k_eControllerAxis_Joystick: + case ::vr::EVRControllerAxisType::k_eControllerAxis_TrackPad: HandleAxisMove(i, axisIdx, state.rAxis[j].x); ++axisIdx; @@ -623,16 +624,16 @@ VRSystemManagerOpenVR::HandleInput() state.rAxis[j].y); ++axisIdx; HandleButtonPress(i, buttonIdx, - vr::ButtonMaskFromId( - static_cast(vr::k_EButton_Axis0 + j)), - state.ulButtonPressed, state.ulButtonTouched); + ::vr::ButtonMaskFromId( + static_cast<::vr::EVRButtonId>(::vr::k_EButton_Axis0 + j)), + state.ulButtonPressed, state.ulButtonTouched); ++buttonIdx; break; - case vr::EVRControllerAxisType::k_eControllerAxis_Trigger: + case ::vr::EVRControllerAxisType::k_eControllerAxis_Trigger: HandleTriggerPress(i, buttonIdx, - vr::ButtonMaskFromId( - static_cast(vr::k_EButton_Axis0 + j)), - state.rAxis[j].x, state.ulButtonPressed, state.ulButtonTouched); + ::vr::ButtonMaskFromId( + static_cast<::vr::EVRButtonId>(::vr::k_EButton_Axis0 + j)), + state.rAxis[j].x, state.ulButtonPressed, state.ulButtonTouched); ++buttonIdx; break; } @@ -641,7 +642,7 @@ VRSystemManagerOpenVR::HandleInput() controller->GetControllerInfo().GetNumAxes()); const uint64_t supportedButtons = mVRSystem->GetUint64TrackedDeviceProperty( - trackedIndex, vr::Prop_SupportedButtons_Uint64); + trackedIndex, ::vr::Prop_SupportedButtons_Uint64); if (supportedButtons & BTN_MASK_FROM_ID(k_EButton_A)) { HandleButtonPress(i, buttonIdx, @@ -700,7 +701,7 @@ VRSystemManagerOpenVR::HandleInput() const ::vr::TrackedDevicePose_t& pose = poses[trackedIndex]; if (pose.bDeviceIsConnected && pose.bPoseIsValid && - pose.eTrackingResult == vr::TrackingResult_Running_OK) { + pose.eTrackingResult == ::vr::TrackingResult_Running_OK) { gfx::Matrix4x4 m; // NOTE! mDeviceToAbsoluteTracking is a 3x4 matrix, not 4x4. But @@ -861,21 +862,21 @@ VRSystemManagerOpenVR::ScanForControllers() return; } - vr::TrackedDeviceIndex_t trackedIndexArray[vr::k_unMaxTrackedDeviceCount]; + ::vr::TrackedDeviceIndex_t trackedIndexArray[::vr::k_unMaxTrackedDeviceCount]; uint32_t newControllerCount = 0; - vr::ETrackedDeviceClass deviceType; + ::vr::ETrackedDeviceClass deviceType; // Basically, we would have HMDs in the tracked devices, // but we are just interested in the controllers. - for (vr::TrackedDeviceIndex_t trackedDevice = vr::k_unTrackedDeviceIndex_Hmd + 1; - trackedDevice < vr::k_unMaxTrackedDeviceCount; ++trackedDevice) { + for (::vr::TrackedDeviceIndex_t trackedDevice = ::vr::k_unTrackedDeviceIndex_Hmd + 1; + trackedDevice < ::vr::k_unMaxTrackedDeviceCount; ++trackedDevice) { if (!mVRSystem->IsTrackedDeviceConnected(trackedDevice)) { continue; } deviceType = mVRSystem->GetTrackedDeviceClass(trackedDevice); - if (deviceType != vr::TrackedDeviceClass_Controller - && deviceType != vr::TrackedDeviceClass_GenericTracker) { + if (deviceType != ::vr::TrackedDeviceClass_Controller + && deviceType != ::vr::TrackedDeviceClass_GenericTracker) { continue; } @@ -892,39 +893,28 @@ VRSystemManagerOpenVR::ScanForControllers() mOpenVRController.Clear(); // Re-adding controllers to VRControllerManager. - for (vr::TrackedDeviceIndex_t i = 0; i < newControllerCount; ++i) { - const vr::TrackedDeviceIndex_t trackedDevice = trackedIndexArray[i]; - const vr::ETrackedControllerRole role = mVRSystem-> + for (::vr::TrackedDeviceIndex_t i = 0; i < newControllerCount; ++i) { + const ::vr::TrackedDeviceIndex_t trackedDevice = trackedIndexArray[i]; + const ::vr::ETrackedControllerRole role = mVRSystem-> GetControllerRoleForTrackedDeviceIndex( trackedDevice); - GamepadHand hand; + uint32_t numButtons = 0; uint32_t numAxes = 0; - - switch(role) { - case vr::ETrackedControllerRole::TrackedControllerRole_Invalid: - hand = GamepadHand::_empty; - break; - case vr::ETrackedControllerRole::TrackedControllerRole_LeftHand: - hand = GamepadHand::Left; - break; - case vr::ETrackedControllerRole::TrackedControllerRole_RightHand: - hand = GamepadHand::Right; - break; - } + const GamepadHand hand = GetGamepadHandFromControllerRole(role); // Scan the axes that the controllers support - for (uint32_t j = 0; j < vr::k_unControllerStateAxisCount; ++j) { + for (uint32_t j = 0; j < ::vr::k_unControllerStateAxisCount; ++j) { const uint32_t supportAxis = mVRSystem->GetInt32TrackedDeviceProperty(trackedDevice, static_cast( - vr::Prop_Axis0Type_Int32 + j)); + ::vr::Prop_Axis0Type_Int32 + j)); switch (supportAxis) { - case vr::EVRControllerAxisType::k_eControllerAxis_Joystick: - case vr::EVRControllerAxisType::k_eControllerAxis_TrackPad: + case ::vr::EVRControllerAxisType::k_eControllerAxis_Joystick: + case ::vr::EVRControllerAxisType::k_eControllerAxis_TrackPad: numAxes += 2; // It has x and y axes. ++numButtons; break; - case vr::k_eControllerAxis_Trigger: + case ::vr::k_eControllerAxis_Trigger: ++numButtons; break; } @@ -932,7 +922,7 @@ VRSystemManagerOpenVR::ScanForControllers() // Scan the buttons that the controllers support const uint64_t supportButtons = mVRSystem->GetUint64TrackedDeviceProperty( - trackedDevice, vr::Prop_SupportedButtons_Uint64); + trackedDevice, ::vr::Prop_SupportedButtons_Uint64); if (supportButtons & BTN_MASK_FROM_ID(k_EButton_A)) { ++numButtons; diff --git a/gfx/vr/gfxVROpenVR.h b/gfx/vr/gfxVROpenVR.h index 034922e44e38..d09b35797a9c 100644 --- a/gfx/vr/gfxVROpenVR.h +++ b/gfx/vr/gfxVROpenVR.h @@ -66,12 +66,12 @@ class VRControllerOpenVR : public VRControllerHost { public: explicit VRControllerOpenVR(dom::GamepadHand aHand, uint32_t aNumButtons, - uint32_t aNumAxes, vr::ETrackedDeviceClass aDeviceType); + uint32_t aNumAxes, ::vr::ETrackedDeviceClass aDeviceType); void SetTrackedIndex(uint32_t aTrackedIndex); uint32_t GetTrackedIndex(); void SetTrigger(float aValue); float GetTrigger(); - void VibrateHaptic(vr::IVRSystem* aVRSystem, + void VibrateHaptic(::vr::IVRSystem* aVRSystem, uint32_t aHapticIndex, double aIntensity, double aDuration, @@ -82,7 +82,7 @@ protected: virtual ~VRControllerOpenVR(); private: - void UpdateVibrateHaptic(vr::IVRSystem* aVRSystem, + void UpdateVibrateHaptic(::vr::IVRSystem* aVRSystem, uint32_t aHapticIndex, double aIntensity, double aDuration, @@ -90,7 +90,7 @@ private: uint32_t aPromiseID); void VibrateHapticComplete(uint32_t aPromiseID); - // The index of tracked devices from vr::IVRSystem. + // The index of tracked devices from ::vr::IVRSystem. uint32_t mTrackedIndex; float mTrigger; nsCOMPtr mVibrateThread; @@ -140,11 +140,13 @@ private: void HandlePoseTracking(uint32_t aControllerIdx, const dom::GamepadPoseState& aPose, VRControllerHost* aController); + dom::GamepadHand GetGamepadHandFromControllerRole( + ::vr::ETrackedControllerRole aRole); // there can only be one RefPtr mOpenVRHMD; nsTArray> mOpenVRController; - vr::IVRSystem *mVRSystem; + ::vr::IVRSystem *mVRSystem; }; } // namespace gfx From 9e638e1eacf587ca1c1bf4eefd47afcf927676a7 Mon Sep 17 00:00:00 2001 From: Daosheng Mu Date: Tue, 18 Apr 2017 15:55:15 +0800 Subject: [PATCH 33/65] Bug 1356452 - Part 3: Support changing gamepad hand property in GamepadManager; r=Lenzak MozReview-Commit-ID: KZx2qJqks6f --HG-- extra : rebase_source : f2d3d70f7394964b07bc45d4db1bfd6b56694e38 --- dom/gamepad/GamepadManager.cpp | 48 +++++++++++++++++++++++++ dom/gamepad/GamepadManager.h | 5 +++ dom/gamepad/ipc/GamepadEventTypes.ipdlh | 7 ++++ 3 files changed, 60 insertions(+) diff --git a/dom/gamepad/GamepadManager.cpp b/dom/gamepad/GamepadManager.cpp index 396cf4f9093b..9e0e9b2857d2 100644 --- a/dom/gamepad/GamepadManager.cpp +++ b/dom/gamepad/GamepadManager.cpp @@ -451,6 +451,49 @@ GamepadManager::NewPoseEvent(uint32_t aIndex, GamepadServiceType aServiceType, } } +void +GamepadManager::NewHandChangeEvent(uint32_t aIndex, GamepadServiceType aServiceType, + GamepadHand aHand) +{ + if (mShuttingDown) { + return; + } + + uint32_t newIndex = GetGamepadIndexWithServiceType(aIndex, aServiceType); + + RefPtr gamepad = GetGamepad(newIndex); + if (!gamepad) { + return; + } + gamepad->SetHand(aHand); + + // Hold on to listeners in a separate array because firing events + // can mutate the mListeners array. + nsTArray> listeners(mListeners); + MOZ_ASSERT(!listeners.IsEmpty()); + + for (uint32_t i = 0; i < listeners.Length(); i++) { + + MOZ_ASSERT(listeners[i]->IsInnerWindow()); + + // Only send events to non-background windows + if (!listeners[i]->AsInner()->IsCurrentInnerWindow() || + listeners[i]->GetOuterWindow()->IsBackground()) { + continue; + } + + bool firstTime = MaybeWindowHasSeenGamepad(listeners[i], newIndex); + + RefPtr listenerGamepad = listeners[i]->GetGamepad(newIndex); + if (listenerGamepad) { + listenerGamepad->SetHand(aHand); + if (firstTime) { + FireConnectionEvent(listeners[i], listenerGamepad, true); + } + } + } +} + void GamepadManager::NewConnectionEvent(uint32_t aIndex, bool aConnected) { @@ -664,6 +707,11 @@ GamepadManager::Update(const GamepadChangeEvent& aEvent) NewPoseEvent(a.index(), a.service_type(), a.pose_state()); return; } + if (aEvent.type() == GamepadChangeEvent::TGamepadHandInformation) { + const GamepadHandInformation& a = aEvent.get_GamepadHandInformation(); + NewHandChangeEvent(a.index(), a.service_type(), a.hand()); + return; + } MOZ_CRASH("We shouldn't be here!"); diff --git a/dom/gamepad/GamepadManager.h b/dom/gamepad/GamepadManager.h index 836ba544ce72..2e86044d5a76 100644 --- a/dom/gamepad/GamepadManager.h +++ b/dom/gamepad/GamepadManager.h @@ -75,6 +75,11 @@ class GamepadManager final : public nsIObserver, void NewPoseEvent(uint32_t aIndex, GamepadServiceType aServiceType, const GamepadPoseState& aState); + // Update the hand of |aHand| for the gamepad at |aIndex| for all + // windows that are listening and visible. + void NewHandChangeEvent(uint32_t aIndex, GamepadServiceType aServiceType, + GamepadHand aHand); + // Synchronize the state of |aGamepad| to match the gamepad stored at |aIndex| void SyncGamepadState(uint32_t aIndex, Gamepad* aGamepad); diff --git a/dom/gamepad/ipc/GamepadEventTypes.ipdlh b/dom/gamepad/ipc/GamepadEventTypes.ipdlh index 128a3b594b79..b13a22e9f937 100644 --- a/dom/gamepad/ipc/GamepadEventTypes.ipdlh +++ b/dom/gamepad/ipc/GamepadEventTypes.ipdlh @@ -49,12 +49,19 @@ struct GamepadPoseInformation { GamepadPoseState pose_state; }; +struct GamepadHandInformation { + uint32_t index; + GamepadServiceType service_type; + GamepadHand hand; +}; + union GamepadChangeEvent { GamepadAdded; GamepadRemoved; GamepadAxisInformation; GamepadButtonInformation; GamepadPoseInformation; + GamepadHandInformation; }; } // namespace dom From 0d1a38ef9ab8fcf3bd3885f7061e40db43b411a5 Mon Sep 17 00:00:00 2001 From: Daosheng Mu Date: Tue, 18 Apr 2017 15:56:08 +0800 Subject: [PATCH 34/65] Bug 1356452 - Part 4: Add gamepad set hand function in Gamepad; r=qdot MozReview-Commit-ID: LrQjMZ6demG --HG-- extra : rebase_source : 56fe3af2ba69be38226b51248ae53a8bf4bbe0c2 --- dom/gamepad/Gamepad.cpp | 6 ++++++ dom/gamepad/Gamepad.h | 1 + 2 files changed, 7 insertions(+) diff --git a/dom/gamepad/Gamepad.cpp b/dom/gamepad/Gamepad.cpp index e86a57054586..9f767a254478 100644 --- a/dom/gamepad/Gamepad.cpp +++ b/dom/gamepad/Gamepad.cpp @@ -106,6 +106,12 @@ Gamepad::SetPose(const GamepadPoseState& aPose) UpdateTimestamp(); } +void +Gamepad::SetHand(GamepadHand aHand) +{ + mHand = aHand; +} + void Gamepad::SyncState(Gamepad* aOther) { diff --git a/dom/gamepad/Gamepad.h b/dom/gamepad/Gamepad.h index e63e51aacbbd..8cbd4f2d689c 100644 --- a/dom/gamepad/Gamepad.h +++ b/dom/gamepad/Gamepad.h @@ -56,6 +56,7 @@ public: void SetAxis(uint32_t aAxis, double aValue); void SetIndex(uint32_t aIndex); void SetPose(const GamepadPoseState& aPose); + void SetHand(GamepadHand aHand); // Make the state of this gamepad equivalent to other. void SyncState(Gamepad* aOther); From 5ec9ae756df378bbe8fdf6113119224a1152c659 Mon Sep 17 00:00:00 2001 From: Daosheng Mu Date: Tue, 18 Apr 2017 15:58:34 +0800 Subject: [PATCH 35/65] Bug 1356452 - Part 5: Detect hand changing at runtime for OpenVR controllers; r=kip MozReview-Commit-ID: AR5zpxryIw6 --HG-- extra : rebase_source : c99f87a1c82b59c106bbb7e1c1c29d2478e2d353 --- gfx/vr/gfxVR.cpp | 12 ++++++++++++ gfx/vr/gfxVR.h | 1 + gfx/vr/gfxVROpenVR.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ gfx/vr/gfxVROpenVR.h | 1 + 4 files changed, 56 insertions(+) diff --git a/gfx/vr/gfxVR.cpp b/gfx/vr/gfxVR.cpp index 1d97d5214fe5..b385047cc80d 100644 --- a/gfx/vr/gfxVR.cpp +++ b/gfx/vr/gfxVR.cpp @@ -115,3 +115,15 @@ VRSystemManager::NewPoseState(uint32_t aIndex, VRManager* vm = VRManager::Get(); vm->NotifyGamepadChange(a); } + +void +VRSystemManager::NewHandChangeEvent(uint32_t aIndex, + const dom::GamepadHand aHand) +{ + dom::GamepadHandInformation a(aIndex, dom::GamepadServiceType::VR, + aHand); + + VRManager* vm = VRManager::Get(); + vm->NotifyGamepadChange(a); +} + diff --git a/gfx/vr/gfxVR.h b/gfx/vr/gfxVR.h index dd2513f52759..f302163d86d3 100644 --- a/gfx/vr/gfxVR.h +++ b/gfx/vr/gfxVR.h @@ -270,6 +270,7 @@ public: double aValue); void NewAxisMove(uint32_t aIndex, uint32_t aAxis, double aValue); void NewPoseState(uint32_t aIndex, const dom::GamepadPoseState& aPose); + void NewHandChangeEvent(uint32_t aIndex, const dom::GamepadHand aHand); void AddGamepad(const VRControllerInfo& controllerInfo); void RemoveGamepad(uint32_t aIndex); diff --git a/gfx/vr/gfxVROpenVR.cpp b/gfx/vr/gfxVROpenVR.cpp index c595b4d44861..3170900b112a 100644 --- a/gfx/vr/gfxVROpenVR.cpp +++ b/gfx/vr/gfxVROpenVR.cpp @@ -404,6 +404,11 @@ VRControllerOpenVR::GetTrigger() } void +VRControllerOpenVR::SetHand(dom::GamepadHand aHand) +{ + mControllerInfo.mHand = aHand; +} + void VRControllerOpenVR::UpdateVibrateHaptic(::vr::IVRSystem* aVRSystem, uint32_t aHapticIndex, @@ -608,6 +613,19 @@ VRSystemManagerOpenVR::HandleInput() mVRSystem->GetTrackedDeviceClass(trackedIndex) == ::vr::TrackedDeviceClass_GenericTracker); + // Sometimes, OpenVR controllers are not located by HMD at the initial time. + // That makes us have to update the hand info at runtime although switching controllers + // to the other hand does not have new changes at the current OpenVR SDK. But, it makes sense + // to detect hand changing at runtime. + const ::vr::ETrackedControllerRole role = mVRSystem-> + GetControllerRoleForTrackedDeviceIndex( + trackedIndex); + const dom::GamepadHand hand = GetGamepadHandFromControllerRole(role); + if (hand != controller->GetHand()) { + controller->SetHand(hand); + NewHandChangeEvent(i, hand); + } + if (mVRSystem->GetControllerState(trackedIndex, &state, sizeof(state))) { for (uint32_t j = 0; j < ::vr::k_unControllerStateAxisCount; ++j) { const uint32_t axisType = mVRSystem->GetInt32TrackedDeviceProperty( @@ -810,6 +828,30 @@ VRSystemManagerOpenVR::HandlePoseTracking(uint32_t aControllerIdx, } } +dom::GamepadHand +VRSystemManagerOpenVR::GetGamepadHandFromControllerRole( + ::vr::ETrackedControllerRole aRole) +{ + dom::GamepadHand hand; + + switch(aRole) { + case ::vr::ETrackedControllerRole::TrackedControllerRole_Invalid: + hand = dom::GamepadHand::_empty; + break; + case ::vr::ETrackedControllerRole::TrackedControllerRole_LeftHand: + hand = dom::GamepadHand::Left; + break; + case ::vr::ETrackedControllerRole::TrackedControllerRole_RightHand: + hand = dom::GamepadHand::Right; + break; + default: + MOZ_ASSERT(false); + break; + } + + return hand; +} + void VRSystemManagerOpenVR::VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex, diff --git a/gfx/vr/gfxVROpenVR.h b/gfx/vr/gfxVROpenVR.h index d09b35797a9c..c96c9079d984 100644 --- a/gfx/vr/gfxVROpenVR.h +++ b/gfx/vr/gfxVROpenVR.h @@ -71,6 +71,7 @@ public: uint32_t GetTrackedIndex(); void SetTrigger(float aValue); float GetTrigger(); + void SetHand(dom::GamepadHand aHand); void VibrateHaptic(::vr::IVRSystem* aVRSystem, uint32_t aHapticIndex, double aIntensity, From f3f1cd175fbec8439d53ab330f1361535200aa72 Mon Sep 17 00:00:00 2001 From: Marco Bonardo Date: Tue, 18 Apr 2017 23:51:05 +0200 Subject: [PATCH 36/65] Bug 1357555 - Properly handle an expiration value of 0 when fetching an icon. r=adw Favicons migrated from the old store have expiration set to 0. The code is not expecting that, since expiration has always been positive, thus those icons are always considered valid and never replaced. They should instead be considered expired. MozReview-Commit-ID: Cz0JB4IbURA --HG-- extra : rebase_source : aae2a477fe52198647a820ceb1db249316c4d72f --- toolkit/components/places/FaviconHelpers.cpp | 4 +-- .../favicons/test_expire_migrated_icons.js | 27 +++++++++++++++++++ .../places/tests/favicons/xpcshell.ini | 1 + .../components/places/tests/head_common.js | 6 +++-- 4 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 toolkit/components/places/tests/favicons/test_expire_migrated_icons.js diff --git a/toolkit/components/places/FaviconHelpers.cpp b/toolkit/components/places/FaviconHelpers.cpp index 52947c58305d..e93549bbde63 100644 --- a/toolkit/components/places/FaviconHelpers.cpp +++ b/toolkit/components/places/FaviconHelpers.cpp @@ -159,6 +159,7 @@ SetIconInfo(const RefPtr& aDB, MOZ_ASSERT(!NS_IsMainThread()); MOZ_ASSERT(aIcon.payloads.Length() > 0); MOZ_ASSERT(!aIcon.spec.IsEmpty()); + MOZ_ASSERT(aIcon.expiration > 0); // There are multiple cases possible at this point: // 1. We must insert some payloads and no payloads exist in the table. This @@ -519,8 +520,7 @@ AsyncFetchAndSetIconForPage::Run() nsresult rv = FetchIconInfo(DB, 0, mIcon); NS_ENSURE_SUCCESS(rv, rv); - bool isInvalidIcon = !mIcon.payloads.Length() || - (mIcon.expiration && PR_Now() > mIcon.expiration); + bool isInvalidIcon = !mIcon.payloads.Length() || PR_Now() > mIcon.expiration; bool fetchIconFromNetwork = mIcon.fetchMode == FETCH_ALWAYS || (mIcon.fetchMode == FETCH_IF_MISSING && isInvalidIcon); diff --git a/toolkit/components/places/tests/favicons/test_expire_migrated_icons.js b/toolkit/components/places/tests/favicons/test_expire_migrated_icons.js new file mode 100644 index 000000000000..d19a8a7fd3a4 --- /dev/null +++ b/toolkit/components/places/tests/favicons/test_expire_migrated_icons.js @@ -0,0 +1,27 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * This file tests that favicons migrated from a previous profile, having a 0 + * expiration, will be properly expired when fetching new ones. + */ + +add_task(function* test_storing_a_normal_16x16_icon() { + const PAGE_URL = "http://places.test"; + yield PlacesTestUtils.addVisits(PAGE_URL); + yield setFaviconForPage(PAGE_URL, SMALLPNG_DATA_URI); + + // Now set expiration to 0 and change the payload. + do_print("Set expiration to 0 and replace favicon data"); + yield PlacesUtils.withConnectionWrapper("Change favicons payload", db => { + return db.execute(`UPDATE moz_icons SET expire_ms = 0, data = "test"`); + }); + + let {data, mimeType} = yield getFaviconDataForPage(PAGE_URL); + Assert.equal(mimeType, "image/png"); + Assert.deepEqual(data, "test".split("").map(c => c.charCodeAt(0))); + + do_print("Refresh favicon"); + yield setFaviconForPage(PAGE_URL, SMALLPNG_DATA_URI, false); + yield compareFavicons("page-icon:" + PAGE_URL, SMALLPNG_DATA_URI); +}); diff --git a/toolkit/components/places/tests/favicons/xpcshell.ini b/toolkit/components/places/tests/favicons/xpcshell.ini index a60ca0bc6822..38442056db23 100644 --- a/toolkit/components/places/tests/favicons/xpcshell.ini +++ b/toolkit/components/places/tests/favicons/xpcshell.ini @@ -24,6 +24,7 @@ support-files = favicon-scale3x160.jpg [test_expireAllFavicons.js] +[test_expire_migrated_icons.js] [test_expire_on_new_icons.js] [test_favicons_conversions.js] [test_favicons_protocols_ref.js] diff --git a/toolkit/components/places/tests/head_common.js b/toolkit/components/places/tests/head_common.js index ac7fe3ed3074..452c11acb511 100644 --- a/toolkit/components/places/tests/head_common.js +++ b/toolkit/components/places/tests/head_common.js @@ -863,15 +863,17 @@ function sortBy(array, prop) { * The page's URL * @param icon * The URL of the favicon to be set. + * @param [optional] forceReload + * Whether to enforce reloading the icon. */ -function setFaviconForPage(page, icon) { +function setFaviconForPage(page, icon, forceReload = true) { let pageURI = page instanceof Ci.nsIURI ? page : NetUtil.newURI(new URL(page).href); let iconURI = icon instanceof Ci.nsIURI ? icon : NetUtil.newURI(new URL(icon).href); return new Promise(resolve => { PlacesUtils.favicons.setAndFetchFaviconForPage( - pageURI, iconURI, true, + pageURI, iconURI, forceReload, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, resolve, Services.scriptSecurityManager.getSystemPrincipal() From 7ebdf5f8b2e40bccecff067b25b00091a97c909e Mon Sep 17 00:00:00 2001 From: Marco Bonardo Date: Wed, 19 Apr 2017 10:19:48 +0200 Subject: [PATCH 37/65] Bug 1357664 - Don't delete all relations to expired icons when updating icons for a specific page. r=adw MozReview-Commit-ID: JYHeuyvrJYp --HG-- extra : rebase_source : d1ba003454b12a3fd688545a995c8f0c56bc95c7 --- toolkit/components/places/FaviconHelpers.cpp | 5 +++-- .../tests/favicons/test_expire_on_new_icons.js | 14 ++++++++++++++ toolkit/components/places/tests/head_common.js | 7 +++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/toolkit/components/places/FaviconHelpers.cpp b/toolkit/components/places/FaviconHelpers.cpp index e93549bbde63..7df0f727a76e 100644 --- a/toolkit/components/places/FaviconHelpers.cpp +++ b/toolkit/components/places/FaviconHelpers.cpp @@ -856,12 +856,13 @@ AsyncAssociateIconToPage::Run() if (mPage.id != 0) { nsCOMPtr stmt; stmt = DB->GetStatement( - "DELETE FROM moz_icons_to_pages WHERE icon_id IN ( " + "DELETE FROM moz_icons_to_pages " + "WHERE icon_id IN ( " "SELECT icon_id FROM moz_icons_to_pages " "JOIN moz_icons i ON icon_id = i.id " "WHERE page_id = :page_id " "AND expire_ms < strftime('%s','now','localtime','start of day','-7 days','utc') * 1000 " - ") " + ") AND page_id = :page_id " ); NS_ENSURE_STATE(stmt); mozStorageStatementScoper scoper(stmt); diff --git a/toolkit/components/places/tests/favicons/test_expire_on_new_icons.js b/toolkit/components/places/tests/favicons/test_expire_on_new_icons.js index 656484b90f35..296ee7f9516f 100644 --- a/toolkit/components/places/tests/favicons/test_expire_on_new_icons.js +++ b/toolkit/components/places/tests/favicons/test_expire_on_new_icons.js @@ -5,6 +5,8 @@ add_task(function* test_replaceFaviconData_validHistoryURI() { const TEST_URL = "http://mozilla.com/" yield PlacesTestUtils.addVisits(TEST_URL); + const TEST_URL2 = "http://test.mozilla.com/" + yield PlacesTestUtils.addVisits(TEST_URL2); let favicons = [ { @@ -31,6 +33,13 @@ add_task(function* test_replaceFaviconData_validHistoryURI() { icon.mimeType, icon.expire); yield setFaviconForPage(TEST_URL, TEST_URL + icon.name); + if (icon.expire != 0) { + PlacesUtils.favicons.replaceFaviconData(NetUtil.newURI(TEST_URL + icon.name), + data, data.length, + icon.mimeType, + icon.expire); + yield setFaviconForPage(TEST_URL2, TEST_URL + icon.name); + } } // Only the second and the third icons should have survived. @@ -40,4 +49,9 @@ add_task(function* test_replaceFaviconData_validHistoryURI() { Assert.equal(yield getFaviconUrlForPage(TEST_URL, 64), TEST_URL + favicons[2].name, "Should retrieve the 64px icon"); + + // The expired icon for page 2 should have survived. + Assert.equal(yield getFaviconUrlForPage(TEST_URL2, 16), + TEST_URL + favicons[0].name, + "Should retrieve the expired 16px icon"); }); diff --git a/toolkit/components/places/tests/head_common.js b/toolkit/components/places/tests/head_common.js index 452c11acb511..71024e7e41e8 100644 --- a/toolkit/components/places/tests/head_common.js +++ b/toolkit/components/places/tests/head_common.js @@ -884,9 +884,12 @@ function setFaviconForPage(page, icon, forceReload = true) { function getFaviconUrlForPage(page, width = 0) { let pageURI = page instanceof Ci.nsIURI ? page : NetUtil.newURI(new URL(page).href); - return new Promise(resolve => { + return new Promise((resolve, reject) => { PlacesUtils.favicons.getFaviconURLForPage(pageURI, iconURI => { - resolve(iconURI.spec); + if (iconURI) + resolve(iconURI.spec); + else + reject("Unable to find an icon for " + pageURI.spec); }, width); }); } From faf7c1b49c56a25c0959956f8452b780a7199720 Mon Sep 17 00:00:00 2001 From: Michael Ratcliffe Date: Wed, 19 Apr 2017 12:44:54 +0100 Subject: [PATCH 38/65] Bug 1356223 - Support scalar telemetry probe types in Telemetry.js r=pbro MozReview-Commit-ID: A2SMdvjy4jp --HG-- extra : rebase_source : 002e47280d926c913150dd1b1286a7730855a024 --- .../test/browser_gcli_telemetry.js | 5 +- devtools/client/framework/test/shared-head.js | 4 ++ devtools/client/shared/telemetry.js | 51 +++++++++++++++---- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/devtools/client/commandline/test/browser_gcli_telemetry.js b/devtools/client/commandline/test/browser_gcli_telemetry.js index 7b4aa0b0226a..a5a9a91e3b9b 100644 --- a/devtools/client/commandline/test/browser_gcli_telemetry.js +++ b/devtools/client/commandline/test/browser_gcli_telemetry.js @@ -79,7 +79,6 @@ function loadTelemetryAndRecordLogs() { info("Mock the Telemetry log function to record logged information"); let Telemetry = require("devtools/client/shared/telemetry"); - Telemetry.prototype.telemetryInfo = {}; Telemetry.prototype._oldlog = Telemetry.prototype.log; Telemetry.prototype.log = function (histogramId, value) { @@ -94,6 +93,8 @@ function loadTelemetryAndRecordLogs() { this.telemetryInfo[histogramId].push(value); } }; + Telemetry.prototype._oldlogScalar = Telemetry.prototype.logScalar; + Telemetry.prototype.logScalar = Telemetry.prototype.log; Telemetry.prototype._oldlogKeyed = Telemetry.prototype.logKeyed; Telemetry.prototype.logKeyed = function (histogramId, key, value) { this.log(`${histogramId}|${key}`, value); @@ -110,8 +111,10 @@ function loadTelemetryAndRecordLogs() { function stopRecordingTelemetryLogs(Telemetry) { info("Stopping Telemetry"); Telemetry.prototype.log = Telemetry.prototype._oldlog; + Telemetry.prototype.logScalar = Telemetry.prototype._oldlogScalar; Telemetry.prototype.logKeyed = Telemetry.prototype._oldlogKeyed; delete Telemetry.prototype._oldlog; + delete Telemetry.prototype._oldlogScalar; delete Telemetry.prototype._oldlogKeyed; delete Telemetry.prototype.telemetryInfo; } diff --git a/devtools/client/framework/test/shared-head.js b/devtools/client/framework/test/shared-head.js index 8faabd264b3d..2288b691166c 100644 --- a/devtools/client/framework/test/shared-head.js +++ b/devtools/client/framework/test/shared-head.js @@ -584,6 +584,8 @@ function loadTelemetryAndRecordLogs() { this.telemetryInfo[histogramId].push(value); } }; + Telemetry.prototype._oldlogScalar = Telemetry.prototype.logScalar; + Telemetry.prototype.logScalar = Telemetry.prototype.log; Telemetry.prototype._oldlogKeyed = Telemetry.prototype.logKeyed; Telemetry.prototype.logKeyed = function (histogramId, key, value) { this.log(`${histogramId}|${key}`, value); @@ -600,8 +602,10 @@ function loadTelemetryAndRecordLogs() { function stopRecordingTelemetryLogs(Telemetry) { info("Stopping Telemetry"); Telemetry.prototype.log = Telemetry.prototype._oldlog; + Telemetry.prototype.logScalar = Telemetry.prototype._oldlogScalar; Telemetry.prototype.logKeyed = Telemetry.prototype._oldlogKeyed; delete Telemetry.prototype._oldlog; + delete Telemetry.prototype._oldlogScalar; delete Telemetry.prototype._oldlogKeyed; delete Telemetry.prototype.telemetryInfo; } diff --git a/devtools/client/shared/telemetry.js b/devtools/client/shared/telemetry.js index 28d2e11777e4..d607c0550fea 100644 --- a/devtools/client/shared/telemetry.js +++ b/devtools/client/shared/telemetry.js @@ -199,6 +199,9 @@ Telemetry.prototype = { if (charts.timerHistogram) { this.startTimer(charts.timerHistogram); } + if (charts.scalar) { + this.logScalar(charts.scalar, 1); + } }, /** @@ -260,14 +263,44 @@ Telemetry.prototype = { * Value to store. */ log: function (histogramId, value) { - if (histogramId) { - try { - let histogram = Services.telemetry.getHistogramById(histogramId); - histogram.add(value); - } catch (e) { - dump("Warning: An attempt was made to write to the " + histogramId + - " histogram, which is not defined in Histograms.json\n"); + if (!histogramId) { + return; + } + + try { + let histogram = Services.telemetry.getHistogramById(histogramId); + histogram.add(value); + } catch (e) { + dump(`Warning: An attempt was made to write to the ${histogramId} ` + + `histogram, which is not defined in Histograms.json\n`); + } + }, + + /** + * Log a value to a scalar. + * + * @param {String} scalarId + * Scalar in which the data is to be stored. + * @param value + * Value to store. + */ + logScalar: function (scalarId, value) { + if (!scalarId) { + return; + } + + try { + if (isNaN(value)) { + dump(`Warning: An attempt was made to write a non-numeric value ` + + `${value} to the ${scalarId} scalar. Only numeric values are ` + + `allowed.`); + + return; } + Services.telemetry.scalarSet(scalarId, value); + } catch (e) { + dump(`Warning: An attempt was made to write to the ${scalarId} ` + + `scalar, which is not defined in Scalars.yaml\n`); } }, @@ -292,8 +325,8 @@ Telemetry.prototype = { histogram.add(key, value); } } catch (e) { - dump("Warning: An attempt was made to write to the " + histogramId + - " histogram, which is not defined in Histograms.json\n"); + dump(`Warning: An attempt was made to write to the ${histogramId} ` + + `histogram, which is not defined in Histograms.json\n`); } } }, From 05f3fde7c3ddd2fb824841959f919b54308151bf Mon Sep 17 00:00:00 2001 From: cku Date: Tue, 18 Apr 2017 23:35:56 +0800 Subject: [PATCH 39/65] Bug 1357432 - Part 1. Move IsLocalRefURL to nsContentUtils to reuse this function. r=heycam IsLocalRefURL is originally designed to be used by URLValue only. Since we need this function in SVGUseElement::LookupHref too, move it to nsContentUtils as a util function. MozReview-Commit-ID: FDjWVbTfB0V --HG-- extra : rebase_source : a3e1133f08ffad59a05c6e829f4ff416b897b917 --- dom/base/nsContentUtils.cpp | 18 +++++++++++++++++- dom/base/nsContentUtils.h | 7 +++++++ layout/style/nsCSSValue.cpp | 18 +----------------- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 615b028384cc..2bb6661dad47 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -10185,7 +10185,7 @@ nsContentUtils::HtmlObjectContentTypeForMIMEType(const nsCString& aMIMEType, } /* static */ already_AddRefed - nsContentUtils::GetEventTargetByLoadInfo(nsILoadInfo* aLoadInfo, TaskCategory aCategory) +nsContentUtils::GetEventTargetByLoadInfo(nsILoadInfo* aLoadInfo, TaskCategory aCategory) { if (NS_WARN_IF(!aLoadInfo)) { return nullptr; @@ -10218,3 +10218,19 @@ nsContentUtils::HtmlObjectContentTypeForMIMEType(const nsCString& aMIMEType, return target.forget(); } + +/* static */ bool +nsContentUtils::IsLocalRefURL(const nsString& aString) +{ + // Find the first non-"C0 controls + space" character. + const char16_t* current = aString.get(); + for (; *current != '\0'; current++) { + if (*current > 0x20) { + // if the first non-"C0 controls + space" character is '#', this is a + // local-ref URL. + return *current == '#'; + } + } + + return false; +} \ No newline at end of file diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index c4dea760576c..e0b38bd41a05 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -2863,6 +2863,13 @@ public: static already_AddRefed GetEventTargetByLoadInfo(nsILoadInfo* aLoadInfo, mozilla::TaskCategory aCategory); + /** + * Detect whether a string is a local-url. + * https://drafts.csswg.org/css-values/#local-urls + */ + static bool + IsLocalRefURL(const nsString& aString); + private: static bool InitializeEventTable(); diff --git a/layout/style/nsCSSValue.cpp b/layout/style/nsCSSValue.cpp index 43d5d9664f1d..005ed92a7cb4 100644 --- a/layout/style/nsCSSValue.cpp +++ b/layout/style/nsCSSValue.cpp @@ -29,22 +29,6 @@ using namespace mozilla; using namespace mozilla::css; -static bool -IsLocalRefURL(const nsString& aString) -{ - // Find the first non-"C0 controls + space" character. - const char16_t* current = aString.get(); - for (; *current != '\0'; current++) { - if (*current > 0x20) { - // if the first non-"C0 controls + space" character is '#', this is a - // local-ref URL. - return *current == '#'; - } - } - - return false; -} - static bool MightHaveRef(const nsString& aString) { @@ -2875,7 +2859,7 @@ css::URLValueData::IsLocalRef() const { if (mIsLocalRef.isNothing()) { // IsLocalRefURL is O(N), use it only when IsLocalRef is called. - mIsLocalRef.emplace(IsLocalRefURL(mString)); + mIsLocalRef.emplace(nsContentUtils::IsLocalRefURL(mString)); } return mIsLocalRef.value(); From 71f1a61edbd630bcb5c75e3391e6d6742454d769 Mon Sep 17 00:00:00 2001 From: cku Date: Thu, 20 Apr 2017 15:58:19 +0800 Subject: [PATCH 40/65] Bug 1357432 - Part 2. Implement nsSVGEffects::GetBaseURLForLocalRef to export local-ref-url-resolving logic. r=heycam ResolveURLUsingLocalRef is designed to be internally used by nsSVGEffects::Get-{SVGEffect}-URI functions. Since we also need it in SVGUseElement::LookupHref, make it public in nsSVGEffects. MozReview-Commit-ID: Hsvs8Uzahrz --HG-- extra : rebase_source : 54698a477a2ebb3f635fb3a77f6bc39b1741b05b --- layout/svg/nsSVGEffects.cpp | 46 ++++++++++++++++++++++++------------- layout/svg/nsSVGEffects.h | 14 ++++++++++- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/layout/svg/nsSVGEffects.cpp b/layout/svg/nsSVGEffects.cpp index 39b4b605035a..de651c693bbe 100644 --- a/layout/svg/nsSVGEffects.cpp +++ b/layout/svg/nsSVGEffects.cpp @@ -910,24 +910,13 @@ nsSVGEffects::InvalidateDirectRenderingObservers(nsIFrame* aFrame, uint32_t aFla } } -static already_AddRefed -ResolveURLUsingLocalRef(nsIFrame* aFrame, const css::URLValueData* aURL) +already_AddRefed +nsSVGEffects::GetBaseURLForLocalRef(nsIContent* content, nsIURI* aDocURI) { - MOZ_ASSERT(aFrame); - - if (!aURL) { - return nullptr; - } - - // Non-local-reference URL. - if (!aURL->IsLocalRef()) { - nsCOMPtr result = aURL->GetURI(); - return result.forget(); - } + MOZ_ASSERT(content); // For a local-reference URL, resolve that fragment against the current // document that relative URLs are resolved against. - nsIContent* content = aFrame->GetContent(); nsCOMPtr baseURI = content->OwnerDoc()->GetDocumentURI(); if (content->IsInAnonymousSubtree()) { @@ -955,12 +944,37 @@ ResolveURLUsingLocalRef(nsIFrame* aFrame, const css::URLValueData* aURL) } } - if (originalURI && aURL->EqualsExceptRef(originalURI)) { - baseURI = originalURI; + if (originalURI) { + bool isEqualsExceptRef = false; + aDocURI->EqualsExceptRef(originalURI, &isEqualsExceptRef); + if (isEqualsExceptRef) { + baseURI = originalURI; + } } } } + return baseURI.forget(); +} + +static already_AddRefed +ResolveURLUsingLocalRef(nsIFrame* aFrame, const css::URLValueData* aURL) +{ + MOZ_ASSERT(aFrame); + + if (!aURL) { + return nullptr; + } + + // Non-local-reference URL. + if (!aURL->IsLocalRef()) { + nsCOMPtr result = aURL->GetURI(); + return result.forget(); + } + + nsCOMPtr baseURI = + nsSVGEffects::GetBaseURLForLocalRef(aFrame->GetContent(), aURL->GetURI()); + return aURL->ResolveLocalRef(baseURI); } diff --git a/layout/svg/nsSVGEffects.h b/layout/svg/nsSVGEffects.h index 0ff9b9734969..c24db6d76d3f 100644 --- a/layout/svg/nsSVGEffects.h +++ b/layout/svg/nsSVGEffects.h @@ -666,11 +666,23 @@ public: static already_AddRefed GetPaintURI(nsIFrame* aFrame, nsStyleSVGPaint nsStyleSVG::* aPaint); - /** + /** * A helper function to resolve SVG mask URL. */ static already_AddRefed GetMaskURI(nsIFrame* aFrame, uint32_t aIndex); + + /** + * Return a baseURL for resolving a local-ref URL. + * + * @param aContent an element which uses a local-ref property. Here are some + * examples: + * + * + * + */ + static already_AddRefed + GetBaseURLForLocalRef(nsIContent* aContent, nsIURI* aDocURI); }; #endif /*NSSVGEFFECTS_H_*/ From 950a617ff23a240e80e4dd1bc92f6b805f42a949 Mon Sep 17 00:00:00 2001 From: cku Date: Wed, 19 Apr 2017 02:06:07 +0800 Subject: [PATCH 41/65] Bug 1357432 - Part 3. Resolve local-ref in SVGUseElement::LookupHref by nsSVGEffects::GetBaseURLForLocalRef. r=heycam MozReview-Commit-ID: CGCwQ73EQA7 --HG-- extra : rebase_source : 3ca8c0f052846ffd197e0d70d7a1e54676871f52 --- dom/svg/SVGUseElement.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dom/svg/SVGUseElement.cpp b/dom/svg/SVGUseElement.cpp index 3275e2c9706a..1874b2a0038b 100644 --- a/dom/svg/SVGUseElement.cpp +++ b/dom/svg/SVGUseElement.cpp @@ -16,6 +16,7 @@ #include "nsContentUtils.h" #include "nsIURI.h" #include "mozilla/URLExtraData.h" +#include "nsSVGEffects.h" NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Use) @@ -422,11 +423,15 @@ SVGUseElement::LookupHref() return; } + nsCOMPtr originURI = + mOriginal ? mOriginal->GetBaseURI() : GetBaseURI(); + nsCOMPtr baseURI = nsContentUtils::IsLocalRefURL(href) + ? nsSVGEffects::GetBaseURLForLocalRef(this, originURI) + : originURI; + nsCOMPtr targetURI; - nsCOMPtr baseURI = mOriginal ? mOriginal->GetBaseURI() : GetBaseURI(); nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href, GetComposedDoc(), baseURI); - mSource.Reset(this, targetURI); } From 9f69435d3a94d88224f184de43919c8eddf745f3 Mon Sep 17 00:00:00 2001 From: cku Date: Tue, 18 Apr 2017 23:58:43 +0800 Subject: [PATCH 42/65] Bug 1357432 - Part 4. Reftest for using local-ref as xlink:href value. r=heycam MozReview-Commit-ID: HoKf7vNSneE --HG-- extra : rebase_source : 8f334483998326398903deb1b8e62e93a910ebc6 --- layout/reftests/svg/reftest.list | 1 + layout/reftests/svg/use-localRef-link.html | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 layout/reftests/svg/use-localRef-link.html diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list index a2f7236905a6..ec8ca4b221c7 100644 --- a/layout/reftests/svg/reftest.list +++ b/layout/reftests/svg/reftest.list @@ -512,6 +512,7 @@ fuzzy-if(skiaContent,1,100) == tspan-xy-anchor-end-01.svg tspan-xy-anchor-end-re == use-localRef-clipPath-01.svg use-localRef-clipPath-01-ref.svg == use-localRef-filter-01.svg use-localRef-filter-01-ref.svg == use-localRef-fill-01.svg use-localRef-fill-01-ref.svg +== use-localRef-link.html pass.svg == use-localRef-stroke-01.svg use-localRef-stroke-01-ref.svg == use-localRef-mask-01.svg use-localRef-mask-01-ref.svg diff --git a/layout/reftests/svg/use-localRef-link.html b/layout/reftests/svg/use-localRef-link.html new file mode 100644 index 000000000000..6f6d6feeb37b --- /dev/null +++ b/layout/reftests/svg/use-localRef-link.html @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + From 5f606637f12448e54d579591e15aa8de20a94af1 Mon Sep 17 00:00:00 2001 From: Michael Ratcliffe Date: Wed, 19 Apr 2017 13:04:12 +0100 Subject: [PATCH 43/65] Bug 1352115 - Add scalars for toolbareyedropper, copyuniquecssselector and copyfullcssselector r=bsmedberg,pbro MozReview-Commit-ID: CeqtJ22GM6M --HG-- extra : rebase_source : d80264c6bb990b754ce96dbcb7010b8de6096701 --- .../browser_inspector_menu-02-copy-items.js | 34 ++++++++++++++- devtools/client/shared/telemetry.js | 6 +-- .../browser_telemetry_button_eyedropper.js | 34 ++++++++------- toolkit/components/telemetry/Scalars.yaml | 42 +++++++++++++++++++ 4 files changed, 96 insertions(+), 20 deletions(-) diff --git a/devtools/client/inspector/test/browser_inspector_menu-02-copy-items.js b/devtools/client/inspector/test/browser_inspector_menu-02-copy-items.js index 57a5dbaa08e7..dc8571d65165 100644 --- a/devtools/client/inspector/test/browser_inspector_menu-02-copy-items.js +++ b/devtools/client/inspector/test/browser_inspector_menu-02-copy-items.js @@ -6,6 +6,8 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ // Test that the various copy items in the context menu works correctly. const TEST_URL = URL_ROOT + "doc_inspector_menu.html"; +const SELECTOR_UNIQUE = "devtools.copy.unique.css.selector.opened"; +const SELECTOR_FULL = "devtools.copy.full.css.selector.opened"; const COPY_ITEMS_TEST_DATA = [ { desc: "copy inner html", @@ -26,7 +28,7 @@ const COPY_ITEMS_TEST_DATA = [ text: "body > div:nth-child(1) > p:nth-child(2)", }, { - desc: "copy css path", + desc: "copy CSS path", id: "node-menu-copycsspath", selector: "[data-id=\"copy\"]", text: "html body div p", @@ -41,7 +43,9 @@ const COPY_ITEMS_TEST_DATA = [ ]; add_task(function* () { + let Telemetry = loadTelemetryAndRecordLogs(); let { inspector } = yield openInspectorForURL(TEST_URL); + for (let {desc, id, selector, text} of COPY_ITEMS_TEST_DATA) { info("Testing " + desc); yield selectNode(selector, inspector); @@ -52,4 +56,32 @@ add_task(function* () { yield waitForClipboardPromise(() => item.click(), text); } + + checkTelemetryResults(Telemetry); + stopRecordingTelemetryLogs(Telemetry); }); + +function checkTelemetryResults(Telemetry) { + let data = Telemetry.prototype.telemetryInfo; + let results = new Map(); + + for (let key in data) { + if (key.toLowerCase() === key) { + let pings = data[key].length; + + results.set(key, pings); + } + } + + is(results.size, 2, "The correct number of scalars were logged"); + + let pings = checkPings(SELECTOR_UNIQUE, results); + is(pings, 1, `${SELECTOR_UNIQUE} has just 1 ping`); + + pings = checkPings(SELECTOR_FULL, results); + is(pings, 1, `${SELECTOR_FULL} has just 1 ping`); +} + +function checkPings(scalarId, results) { + return results.get(scalarId); +} diff --git a/devtools/client/shared/telemetry.js b/devtools/client/shared/telemetry.js index d607c0550fea..51dc9d81d4d1 100644 --- a/devtools/client/shared/telemetry.js +++ b/devtools/client/shared/telemetry.js @@ -138,13 +138,13 @@ Telemetry.prototype = { histogram: "DEVTOOLS_PICKER_EYEDROPPER_OPENED_COUNT", }, toolbareyedropper: { - histogram: "DEVTOOLS_TOOLBAR_EYEDROPPER_OPENED_COUNT", + scalar: "devtools.toolbar.eyedropper.opened", }, copyuniquecssselector: { - histogram: "DEVTOOLS_COPY_UNIQUE_CSS_SELECTOR_OPENED_COUNT", + scalar: "devtools.copy.unique.css.selector.opened", }, copyfullcssselector: { - histogram: "DEVTOOLS_COPY_FULL_CSS_SELECTOR_OPENED_COUNT", + scalar: "devtools.copy.full.css.selector.opened", }, developertoolbar: { histogram: "DEVTOOLS_DEVELOPERTOOLBAR_OPENED_COUNT", diff --git a/devtools/client/shared/test/browser_telemetry_button_eyedropper.js b/devtools/client/shared/test/browser_telemetry_button_eyedropper.js index 76546ce8312f..95966bd2ee5b 100644 --- a/devtools/client/shared/test/browser_telemetry_button_eyedropper.js +++ b/devtools/client/shared/test/browser_telemetry_button_eyedropper.js @@ -4,6 +4,7 @@ const TEST_URI = "data:text/html;charset=utf-8," + "

browser_telemetry_button_eyedropper.js

test
"; +const EYEDROPPER_OPENED = "devtools.toolbar.eyedropper.opened"; add_task(function* () { yield addTab(TEST_URI); @@ -27,26 +28,27 @@ function* testButton(toolbox, Telemetry) { // only concerned about testing the telemetry probe. yield toolbox.getPanel("inspector").showEyeDropper(); - checkResults("_EYEDROPPER_", Telemetry); + checkTelemetryResults(Telemetry); } -function checkResults(histIdFocus, Telemetry) { - let result = Telemetry.prototype.telemetryInfo; +function checkTelemetryResults(Telemetry) { + let data = Telemetry.prototype.telemetryInfo; + let results = new Map(); - for (let [histId, value] of Object.entries(result)) { - if (histId.startsWith("DEVTOOLS_INSPECTOR_") || - !histId.includes(histIdFocus)) { - // Inspector stats are tested in - // browser_telemetry_toolboxtabs_{toolname}.js so we skip them here - // because we only open the inspector once for this test. - continue; - } + for (let key in data) { + if (key.toLowerCase() === key) { + let pings = data[key].length; - if (histId.endsWith("OPENED_COUNT")) { - is(value.length, 1, histId + " has one entry"); - - let okay = value.every(element => element === true); - ok(okay, "All " + histId + " entries are === true"); + results.set(key, pings); } } + + is(results.size, 1, "The correct number of scalars were logged"); + + let pings = checkPings(EYEDROPPER_OPENED, results); + is(pings, 1, `${EYEDROPPER_OPENED} has just 1 ping`); +} + +function checkPings(scalarId, results) { + return results.get(scalarId); } diff --git a/toolkit/components/telemetry/Scalars.yaml b/toolkit/components/telemetry/Scalars.yaml index 965def7a658e..c2e4af3bf1e8 100644 --- a/toolkit/components/telemetry/Scalars.yaml +++ b/toolkit/components/telemetry/Scalars.yaml @@ -536,3 +536,45 @@ dom.contentprocess: release_channel_collection: opt-in record_in_processes: - 'main' + +devtools.toolbar.eyedropper: + opened: + bug_numbers: + - 1247985 + - 1352115 + description: Number of times the DevTools Eyedropper has been opened via the inspector toolbar. + expires: never + kind: uint + notification_emails: + - dev-developer-tools@lists.mozilla.org + release_channel_collection: opt-out + record_in_processes: + - 'main' + +devtools.copy.unique.css.selector: + opened: + bug_numbers: + - 1323700 + - 1352115 + description: Number of times the DevTools copy unique CSS selector has been used. + expires: "57" + kind: uint + notification_emails: + - dev-developer-tools@lists.mozilla.org + release_channel_collection: opt-out + record_in_processes: + - 'main' + +devtools.copy.full.css.selector: + opened: + bug_numbers: + - 1323700 + - 1352115 + description: Number of times the DevTools copy full CSS selector has been used. + expires: "57" + kind: uint + notification_emails: + - dev-developer-tools@lists.mozilla.org + release_channel_collection: opt-out + record_in_processes: + - 'main' From 302d82c85a0a8c3a587fd2137db5c378470859b2 Mon Sep 17 00:00:00 2001 From: JW Wang Date: Fri, 14 Apr 2017 17:13:36 +0800 Subject: [PATCH 44/65] Bug 1356530 - Change the type of MediaData::mTime to TimeUnit since int64_t is ambiguous. r=kaku MozReview-Commit-ID: 4bVeqIuWO2O --HG-- extra : rebase_source : d504ac15a6dc59ad42f3ab80faf23f629d74315f extra : intermediate-source : 6e52995b6c8146451d98dffc62f6907755dc856e extra : source : 82d2649cdafb5a6389f6858c23578811933580c9 --- dom/media/ADTSDemuxer.cpp | 6 +- dom/media/MP3Demuxer.cpp | 6 +- dom/media/MediaData.cpp | 2 +- dom/media/MediaData.h | 13 ++-- dom/media/MediaDecoderStateMachine.cpp | 28 ++++---- dom/media/MediaFormatReader.cpp | 34 +++++----- dom/media/MediaQueue.h | 4 +- dom/media/android/AndroidMediaReader.cpp | 9 +-- dom/media/flac/FlacDemuxer.cpp | 6 +- dom/media/fmp4/MP4Demuxer.cpp | 17 ++--- dom/media/gmp/ChromiumCDMParent.cpp | 4 +- dom/media/gtest/TestMP4Demuxer.cpp | 6 +- dom/media/ipc/VideoDecoderChild.cpp | 2 +- dom/media/ipc/VideoDecoderParent.cpp | 5 +- dom/media/mediasink/AudioSink.cpp | 9 +-- dom/media/mediasink/DecodedStream.cpp | 13 ++-- dom/media/mediasink/VideoSink.cpp | 12 ++-- dom/media/mediasource/MediaSourceDemuxer.cpp | 2 +- dom/media/mediasource/TrackBuffersManager.cpp | 64 ++++++++----------- dom/media/ogg/OggCodecState.cpp | 2 +- dom/media/ogg/OggDemuxer.cpp | 7 +- .../platforms/agnostic/BlankDecoderModule.cpp | 6 +- .../platforms/agnostic/NullDecoderModule.cpp | 2 +- dom/media/platforms/agnostic/OpusDecoder.cpp | 7 +- .../platforms/agnostic/TheoraDecoder.cpp | 2 +- dom/media/platforms/agnostic/VPXDecoder.cpp | 4 +- .../platforms/agnostic/VorbisDecoder.cpp | 7 +- dom/media/platforms/agnostic/WAVDecoder.cpp | 2 +- .../agnostic/gmp/GMPVideoDecoder.cpp | 2 +- .../platforms/android/RemoteDataDecoder.cpp | 4 +- dom/media/platforms/apple/AppleATDecoder.cpp | 6 +- dom/media/platforms/apple/AppleVTDecoder.cpp | 4 +- dom/media/platforms/apple/AppleVTDecoder.h | 2 +- .../platforms/ffmpeg/FFmpegAudioDecoder.cpp | 2 +- .../platforms/ffmpeg/FFmpegVideoDecoder.cpp | 5 +- dom/media/platforms/omx/OmxDataDecoder.cpp | 2 +- dom/media/platforms/omx/OmxPromiseLayer.cpp | 2 +- .../platforms/wmf/WMFAudioMFTManager.cpp | 2 +- .../platforms/wmf/WMFVideoMFTManager.cpp | 6 +- dom/media/wave/WaveDemuxer.cpp | 6 +- dom/media/webm/WebMDemuxer.cpp | 22 +++---- media/libstagefright/binding/Index.cpp | 2 +- 42 files changed, 170 insertions(+), 178 deletions(-) diff --git a/dom/media/ADTSDemuxer.cpp b/dom/media/ADTSDemuxer.cpp index 2b1ab372595d..8963004b3898 100644 --- a/dom/media/ADTSDemuxer.cpp +++ b/dom/media/ADTSDemuxer.cpp @@ -752,12 +752,12 @@ ADTSTrackDemuxer::GetNextFrame(const adts::Frame& aFrame) UpdateState(aFrame); - frame->mTime = Duration(mFrameIndex - 1).ToMicroseconds(); + frame->mTime = Duration(mFrameIndex - 1); frame->mDuration = Duration(1); - frame->mTimecode = media::TimeUnit::FromMicroseconds(frame->mTime); + frame->mTimecode = frame->mTime; frame->mKeyframe = true; - MOZ_ASSERT(frame->mTime >= 0); + MOZ_ASSERT(!frame->mTime.IsNegative()); MOZ_ASSERT(frame->mDuration.IsPositive()); ADTSLOGV("GetNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64 diff --git a/dom/media/MP3Demuxer.cpp b/dom/media/MP3Demuxer.cpp index 1bf9e416da98..2a7df252637b 100644 --- a/dom/media/MP3Demuxer.cpp +++ b/dom/media/MP3Demuxer.cpp @@ -604,12 +604,12 @@ MP3TrackDemuxer::GetNextFrame(const MediaByteRange& aRange) UpdateState(aRange); - frame->mTime = Duration(mFrameIndex - 1).ToMicroseconds(); + frame->mTime = Duration(mFrameIndex - 1); frame->mDuration = Duration(1); - frame->mTimecode = media::TimeUnit::FromMicroseconds(frame->mTime); + frame->mTimecode = frame->mTime; frame->mKeyframe = true; - MOZ_ASSERT(frame->mTime >= 0); + MOZ_ASSERT(!frame->mTime.IsNegative()); MOZ_ASSERT(frame->mDuration.IsPositive()); if (mNumParsedFrames == 1) { diff --git a/dom/media/MediaData.cpp b/dom/media/MediaData.cpp index fa40620a6e35..a8c05ce4700f 100644 --- a/dom/media/MediaData.cpp +++ b/dom/media/MediaData.cpp @@ -237,7 +237,7 @@ VideoData::UpdateTimestamp(const TimeUnit& aTimestamp) auto updatedDuration = GetEndTime() - aTimestamp; MOZ_ASSERT(!updatedDuration.IsNegative()); - mTime = aTimestamp.ToMicroseconds(); + mTime = aTimestamp; mDuration = updatedDuration; } diff --git a/dom/media/MediaData.h b/dom/media/MediaData.h index 63d4829cae4f..9eb6e768ccd9 100644 --- a/dom/media/MediaData.h +++ b/dom/media/MediaData.h @@ -294,7 +294,7 @@ public: uint32_t aFrames) : mType(aType) , mOffset(aOffset) - , mTime(aTimestamp) + , mTime(media::TimeUnit::FromMicroseconds(aTimestamp)) , mTimecode(media::TimeUnit::FromMicroseconds(aTimestamp)) , mDuration(media::TimeUnit::FromMicroseconds(aDuration)) , mFrames(aFrames) @@ -308,8 +308,8 @@ public: // Approximate byte offset where this data was demuxed from its media. int64_t mOffset; - // Start time of sample, in microseconds. - int64_t mTime; + // Start time of sample. + media::TimeUnit mTime; // Codec specific internal time code. For Ogg based codecs this is the // granulepos. @@ -325,13 +325,13 @@ public: media::TimeUnit GetEndTime() const { - return media::TimeUnit::FromMicroseconds(mTime) + mDuration; + return mTime + mDuration; } bool AdjustForStartTime(int64_t aStartTime) { - mTime = mTime - aStartTime; - return mTime >= 0; + mTime = mTime - media::TimeUnit::FromMicroseconds(aStartTime); + return !mTime.IsNegative(); } template @@ -352,7 +352,6 @@ protected: MediaData(Type aType, uint32_t aFrames) : mType(aType) , mOffset(0) - , mTime(0) , mFrames(aFrames) , mKeyframe(false) { diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 59ba780c90ea..cedcfdaa2c3d 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -1237,8 +1237,8 @@ private: return seekTime; } - const int64_t audioStart = audio ? audio->mTime : INT64_MAX; - const int64_t videoStart = video ? video->mTime : INT64_MAX; + const int64_t audioStart = audio ? audio->mTime.ToMicroseconds() : INT64_MAX; + const int64_t videoStart = video ? video->mTime.ToMicroseconds() : INT64_MAX; const int64_t audioGap = std::abs(audioStart - seekTime.ToMicroseconds()); const int64_t videoGap = std::abs(videoStart - seekTime.ToMicroseconds()); return TimeUnit::FromMicroseconds( @@ -1314,7 +1314,7 @@ private: { if (mSeekJob.mTarget->IsFast() && mSeekJob.mTarget->GetTime() > mCurrentTimeBeforeSeek - && aSample->mTime < mCurrentTimeBeforeSeek.ToMicroseconds()) { + && aSample->mTime < mCurrentTimeBeforeSeek) { // We are doing a fastSeek, but we ended up *before* the previous // playback position. This is surprising UX, so switch to an accurate // seek and decode to the seek target. This is not conformant to the @@ -1335,7 +1335,7 @@ private: return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR; } - auto audioTime = TimeUnit::FromMicroseconds(aAudio->mTime); + auto audioTime = aAudio->mTime; if (audioTime + sampleDuration <= mSeekJob.mTarget->GetTime()) { // Our seek target lies after the frames in this AudioData. Don't // push it onto the audio queue, and keep decoding forwards. @@ -1405,18 +1405,18 @@ private: { MOZ_ASSERT(aVideo); SLOG("DropVideoUpToSeekTarget() frame [%" PRId64 ", %" PRId64 "]", - aVideo->mTime, aVideo->GetEndTime().ToMicroseconds()); + aVideo->mTime.ToMicroseconds(), aVideo->GetEndTime().ToMicroseconds()); const auto target = mSeekJob.mTarget->GetTime(); // If the frame end time is less than the seek target, we won't want // to display this frame after the seek, so discard it. if (target >= aVideo->GetEndTime()) { SLOG("DropVideoUpToSeekTarget() pop video frame [%" PRId64 ", %" PRId64 "] target=%" PRId64, - aVideo->mTime, aVideo->GetEndTime().ToMicroseconds(), + aVideo->mTime.ToMicroseconds(), aVideo->GetEndTime().ToMicroseconds(), target.ToMicroseconds()); mFirstVideoFrameAfterSeek = aVideo; } else { - if (target.ToMicroseconds() >= aVideo->mTime && + if (target >= aVideo->mTime && aVideo->GetEndTime() >= target) { // The seek target lies inside this frame's time slice. Adjust the // frame's start time to match the seek target. @@ -1426,7 +1426,7 @@ private: SLOG("DropVideoUpToSeekTarget() found video frame [%" PRId64 ", %" PRId64 "] " "containing target=%" PRId64, - aVideo->mTime, aVideo->GetEndTime().ToMicroseconds(), + aVideo->mTime.ToMicroseconds(), aVideo->GetEndTime().ToMicroseconds(), target.ToMicroseconds()); MOZ_ASSERT(VideoQueue().GetSize() == 0, @@ -1475,7 +1475,7 @@ static void DiscardFrames(MediaQueue& aQueue, const Function& aCompare) { while(aQueue.GetSize() > 0) { - if (aCompare(aQueue.PeekFront()->mTime)) { + if (aCompare(aQueue.PeekFront()->mTime.ToMicroseconds())) { RefPtr releaseMe = aQueue.PopFront(); continue; } @@ -1575,7 +1575,7 @@ private: MOZ_ASSERT(!mSeekJob.mPromise.IsEmpty(), "Seek shouldn't be finished"); MOZ_ASSERT(NeedMoreVideo()); - if (aVideo->mTime > mCurrentTime.ToMicroseconds()) { + if (aVideo->mTime > mCurrentTime) { mMaster->PushVideo(aVideo); FinishSeek(); } else { @@ -1667,7 +1667,7 @@ private: { RefPtr data = VideoQueue().PeekFront(); if (data) { - mSeekJob.mTarget->SetTime(TimeUnit::FromMicroseconds(data->mTime)); + mSeekJob.mTarget->SetTime(data->mTime); } else { MOZ_ASSERT(VideoQueue().AtEndOfStream()); mSeekJob.mTarget->SetTime(mDuration); @@ -3177,7 +3177,8 @@ MediaDecoderStateMachine::RequestAudioData() // audio->GetEndTime() is not always mono-increasing in chained ogg. mDecodedAudioEndTime = std::max( aAudio->GetEndTime(), mDecodedAudioEndTime); - LOGV("OnAudioDecoded [%" PRId64 ",%" PRId64 "]", aAudio->mTime, + LOGV("OnAudioDecoded [%" PRId64 ",%" PRId64 "]", + aAudio->mTime.ToMicroseconds(), aAudio->GetEndTime().ToMicroseconds()); mStateObj->HandleAudioDecoded(aAudio); }, @@ -3223,7 +3224,8 @@ MediaDecoderStateMachine::RequestVideoData(bool aSkipToNextKeyframe, // Handle abnormal or negative timestamps. mDecodedVideoEndTime = std::max( mDecodedVideoEndTime, aVideo->GetEndTime()); - LOGV("OnVideoDecoded [%" PRId64 ",%" PRId64 "]", aVideo->mTime, + LOGV("OnVideoDecoded [%" PRId64 ",%" PRId64 "]", + aVideo->mTime.ToMicroseconds(), aVideo->GetEndTime().ToMicroseconds()); mStateObj->HandleVideoDecoded(aVideo, videoDecodeStartTime); }, diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index 0f02cc4297e3..45dae0dee5a5 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -1724,7 +1724,7 @@ MediaFormatReader::NotifyNewOutput( auto& decoder = GetDecoderData(aTrack); for (auto& sample : aResults) { LOGV("Received new %s sample time:%" PRId64 " duration:%" PRId64, - TrackTypeToStr(aTrack), sample->mTime, + TrackTypeToStr(aTrack), sample->mTime.ToMicroseconds(), sample->mDuration.ToMicroseconds()); decoder.mOutput.AppendElement(sample); decoder.mNumSamplesOutput++; @@ -2011,19 +2011,19 @@ MediaFormatReader::HandleDemuxedSamples( if (sample->mKeyframe) { ScheduleUpdate(aTrack); } else { - auto time = TimeInterval( - TimeUnit::FromMicroseconds(sample->mTime), sample->GetEndTime()); + auto time = TimeInterval(sample->mTime, sample->GetEndTime()); InternalSeekTarget seekTarget = decoder.mTimeThreshold.refOr(InternalSeekTarget(time, false)); LOG("Stream change occurred on a non-keyframe. Seeking to:%" PRId64, - sample->mTime); + sample->mTime.ToMicroseconds()); InternalSeek(aTrack, seekTarget); } return; } LOGV("Input:%" PRId64 " (dts:%" PRId64 " kf:%d)", - sample->mTime, sample->mTimecode.ToMicroseconds(), sample->mKeyframe); + sample->mTime.ToMicroseconds(), sample->mTimecode.ToMicroseconds(), + sample->mKeyframe); decoder.mNumSamplesInput++; decoder.mSizeOfQueue++; if (aTrack == TrackInfo::kVideoTrack) { @@ -2186,7 +2186,7 @@ MediaFormatReader::Update(TrackType aTrack) while (decoder.mTimeThreshold && decoder.mOutput.Length()) { RefPtr& output = decoder.mOutput[0]; InternalSeekTarget target = decoder.mTimeThreshold.ref(); - media::TimeUnit time = media::TimeUnit::FromMicroseconds(output->mTime); + media::TimeUnit time = output->mTime; if (time >= target.Time()) { // We have reached our internal seek target. decoder.mTimeThreshold.reset(); @@ -2196,7 +2196,7 @@ MediaFormatReader::Update(TrackType aTrack) if (time < target.Time() || (target.mDropTarget && target.Contains(time))) { LOGV("Internal Seeking: Dropping %s frame time:%f wanted:%f (kf:%d)", TrackTypeToStr(aTrack), - media::TimeUnit::FromMicroseconds(output->mTime).ToSeconds(), + output->mTime.ToSeconds(), target.Time().ToSeconds(), output->mKeyframe); decoder.mOutput.RemoveElementAt(0); @@ -2206,7 +2206,8 @@ MediaFormatReader::Update(TrackType aTrack) while (decoder.mOutput.Length() && decoder.mOutput[0]->mType == MediaData::NULL_DATA) { - LOGV("Dropping null data. Time: %" PRId64, decoder.mOutput[0]->mTime); + LOGV("Dropping null data. Time: %" PRId64, + decoder.mOutput[0]->mTime.ToMicroseconds()); decoder.mOutput.RemoveElementAt(0); decoder.mSizeOfQueue -= 1; } @@ -2218,8 +2219,7 @@ MediaFormatReader::Update(TrackType aTrack) decoder.mOutput.RemoveElementAt(0); decoder.mSizeOfQueue -= 1; decoder.mLastSampleTime = - Some(TimeInterval(TimeUnit::FromMicroseconds(output->mTime), - output->GetEndTime())); + Some(TimeInterval(output->mTime, output->GetEndTime())); decoder.mNumSamplesOutputTotal++; ReturnOutput(output, aTrack); // We have a decoded sample ready to be returned. @@ -2229,17 +2229,17 @@ MediaFormatReader::Update(TrackType aTrack) a.mStats.mDecodedFrames = static_cast(delta); mLastReportedNumDecodedFrames = decoder.mNumSamplesOutputTotal; if (output->mKeyframe) { - if (mPreviousDecodedKeyframeTime_us < output->mTime) { + if (mPreviousDecodedKeyframeTime_us < output->mTime.ToMicroseconds()) { // There is a previous keyframe -> Record inter-keyframe stats. uint64_t segment_us = - output->mTime - mPreviousDecodedKeyframeTime_us; + output->mTime.ToMicroseconds() - mPreviousDecodedKeyframeTime_us; a.mStats.mInterKeyframeSum_us += segment_us; a.mStats.mInterKeyframeCount += 1; if (a.mStats.mInterKeyFrameMax_us < segment_us) { a.mStats.mInterKeyFrameMax_us = segment_us; } } - mPreviousDecodedKeyframeTime_us = output->mTime; + mPreviousDecodedKeyframeTime_us = output->mTime.ToMicroseconds(); } nsCString error; mVideo.mIsHardwareAccelerated = @@ -2379,7 +2379,7 @@ MediaFormatReader::ReturnOutput(MediaData* aData, TrackType aTrack) MOZ_ASSERT(GetDecoderData(aTrack).HasPromise()); MOZ_DIAGNOSTIC_ASSERT(aData->mType != MediaData::NULL_DATA); LOG("Resolved data promise for %s [%" PRId64 ", %" PRId64 "]", TrackTypeToStr(aTrack), - aData->mTime, aData->GetEndTime().ToMicroseconds()); + aData->mTime.ToMicroseconds(), aData->GetEndTime().ToMicroseconds()); if (aTrack == TrackInfo::kAudioTrack) { AudioData* audioData = static_cast(aData); @@ -2506,8 +2506,7 @@ MediaFormatReader::DropDecodedSamples(TrackType aTrack) auto& decoder = GetDecoderData(aTrack); size_t lengthDecodedQueue = decoder.mOutput.Length(); if (lengthDecodedQueue && decoder.mTimeThreshold.isSome()) { - TimeUnit time = - TimeUnit::FromMicroseconds(decoder.mOutput.LastElement()->mTime); + TimeUnit time = decoder.mOutput.LastElement()->mTime; if (time >= decoder.mTimeThreshold.ref().Time()) { // We would have reached our internal seek target. decoder.mTimeThreshold.reset(); @@ -3102,8 +3101,7 @@ MediaFormatReader::OnFirstDemuxCompleted( auto& decoder = GetDecoderData(aType); MOZ_ASSERT(decoder.mFirstDemuxedSampleTime.isNothing()); - decoder.mFirstDemuxedSampleTime.emplace( - TimeUnit::FromMicroseconds(aSamples->mSamples[0]->mTime)); + decoder.mFirstDemuxedSampleTime.emplace(aSamples->mSamples[0]->mTime); MaybeResolveMetadataPromise(); } diff --git a/dom/media/MediaQueue.h b/dom/media/MediaQueue.h index 253aeadfa9fe..ad99303521b0 100644 --- a/dom/media/MediaQueue.h +++ b/dom/media/MediaQueue.h @@ -47,7 +47,7 @@ public: MOZ_ASSERT(!mEndOfStream); MOZ_ASSERT(aItem); NS_ADDREF(aItem); - MOZ_ASSERT(aItem->GetEndTime().ToMicroseconds() >= aItem->mTime); + MOZ_ASSERT(aItem->GetEndTime() >= aItem->mTime); nsDeque::Push(aItem); mPushEvent.Notify(RefPtr(aItem)); } @@ -104,7 +104,7 @@ public: } T* last = static_cast(nsDeque::Peek()); T* first = static_cast(nsDeque::PeekFront()); - return last->GetEndTime().ToMicroseconds() - first->mTime; + return (last->GetEndTime() - first->mTime).ToMicroseconds(); } void LockedForEach(nsDequeFunctor& aFunctor) const { diff --git a/dom/media/android/AndroidMediaReader.cpp b/dom/media/android/AndroidMediaReader.cpp index 7cf4c39988f4..9d0221f93eac 100644 --- a/dom/media/android/AndroidMediaReader.cpp +++ b/dom/media/android/AndroidMediaReader.cpp @@ -141,7 +141,8 @@ bool AndroidMediaReader::DecodeVideoFrame(bool& aKeyframeSkip, if (mLastVideoFrame) { int64_t durationUs; mPlugin->GetDuration(mPlugin, &durationUs); - durationUs = std::max(durationUs - mLastVideoFrame->mTime, 0); + durationUs = std::max( + durationUs - mLastVideoFrame->mTime.ToMicroseconds(), 0); mLastVideoFrame->UpdateDuration(TimeUnit::FromMicroseconds(durationUs)); mVideoQueue.Push(mLastVideoFrame); mLastVideoFrame = nullptr; @@ -247,8 +248,8 @@ bool AndroidMediaReader::DecodeVideoFrame(bool& aKeyframeSkip, // Calculate the duration as the timestamp of the current frame minus the // timestamp of the previous frame. We can then return the previously // decoded frame, and it will have a valid timestamp. - int64_t duration = v->mTime - mLastVideoFrame->mTime; - mLastVideoFrame->UpdateDuration(TimeUnit::FromMicroseconds(duration)); + auto duration = v->mTime - mLastVideoFrame->mTime; + mLastVideoFrame->UpdateDuration(duration); // We have the start time of the next frame, so we can push the previous // frame into the queue, except if the end time is below the threshold, @@ -320,7 +321,7 @@ AndroidMediaReader::Seek(const SeekTarget& aTarget) RefPtr self = this; DecodeToFirstVideoData()->Then(OwnerThread(), __func__, [self] (MediaData* v) { self->mSeekRequest.Complete(); - self->mAudioSeekTimeUs = v->mTime; + self->mAudioSeekTimeUs = v->mTime.ToMicroseconds(); self->mSeekPromise.Resolve(media::TimeUnit::FromMicroseconds(self->mAudioSeekTimeUs), __func__); }, [self, aTarget] () { self->mSeekRequest.Complete(); diff --git a/dom/media/flac/FlacDemuxer.cpp b/dom/media/flac/FlacDemuxer.cpp index 48c02dbbba47..85e0e688bb28 100644 --- a/dom/media/flac/FlacDemuxer.cpp +++ b/dom/media/flac/FlacDemuxer.cpp @@ -980,13 +980,13 @@ FlacTrackDemuxer::GetNextFrame(const flac::Frame& aFrame) return nullptr; } - frame->mTime = aFrame.Time().ToMicroseconds(); + frame->mTime = aFrame.Time(); frame->mDuration = aFrame.Duration(); - frame->mTimecode = TimeUnit::FromMicroseconds(frame->mTime); + frame->mTimecode = frame->mTime; frame->mOffset = aFrame.Offset(); frame->mKeyframe = true; - MOZ_ASSERT(frame->mTime >= 0); + MOZ_ASSERT(!frame->mTime.IsNegative()); MOZ_ASSERT(!frame->mDuration.IsNegative()); return frame.forget(); diff --git a/dom/media/fmp4/MP4Demuxer.cpp b/dom/media/fmp4/MP4Demuxer.cpp index fe10a21c0436..c122daa66d1d 100644 --- a/dom/media/fmp4/MP4Demuxer.cpp +++ b/dom/media/fmp4/MP4Demuxer.cpp @@ -411,10 +411,10 @@ MP4TrackDemuxer::EnsureUpToDateIndex() RefPtr MP4TrackDemuxer::Seek(const media::TimeUnit& aTime) { - int64_t seekTime = aTime.ToMicroseconds(); + auto seekTime = aTime; mQueuedSample = nullptr; - mIterator->Seek(seekTime); + mIterator->Seek(seekTime.ToMicroseconds()); // Check what time we actually seeked to. RefPtr sample; @@ -436,8 +436,7 @@ MP4TrackDemuxer::Seek(const media::TimeUnit& aTime) SetNextKeyFrameTime(); - return SeekPromise::CreateAndResolve( - media::TimeUnit::FromMicroseconds(seekTime), __func__); + return SeekPromise::CreateAndResolve(seekTime, __func__); } already_AddRefed @@ -461,7 +460,8 @@ MP4TrackDemuxer::GetNextSample() NS_WARNING(nsPrintfCString("Frame incorrectly marked as %skeyframe " "@ pts:%" PRId64 " dur:%" PRId64 " dts:%" PRId64, - keyframe ? "" : "non-", sample->mTime, + keyframe ? "" : "non-", + sample->mTime.ToMicroseconds(), sample->mDuration.ToMicroseconds(), sample->mTimecode.ToMicroseconds()) .get()); @@ -473,7 +473,8 @@ MP4TrackDemuxer::GetNextSample() NS_WARNING( nsPrintfCString("Invalid H264 frame @ pts:%" PRId64 " dur:%" PRId64 " dts:%" PRId64, - sample->mTime, sample->mDuration.ToMicroseconds(), + sample->mTime.ToMicroseconds(), + sample->mDuration.ToMicroseconds(), sample->mTimecode.ToMicroseconds()) .get()); // We could reject the sample now, however demuxer errors are fatal. @@ -540,7 +541,7 @@ MP4TrackDemuxer::GetSamples(int32_t aNumSamples) if (mNextKeyframeTime.isNothing() || samples->mSamples.LastElement()->mTime - >= mNextKeyframeTime.value().ToMicroseconds()) { + >= mNextKeyframeTime.value()) { SetNextKeyFrameTime(); } return SamplesPromise::CreateAndResolve(samples, __func__); @@ -590,7 +591,7 @@ MP4TrackDemuxer::SkipToNextRandomAccessPoint( RefPtr sample; while (!found && (sample = GetNextSample())) { parsed++; - if (sample->mKeyframe && sample->mTime >= aTimeThreshold.ToMicroseconds()) { + if (sample->mKeyframe && sample->mTime >= aTimeThreshold) { found = true; mQueuedSample = sample; } diff --git a/dom/media/gmp/ChromiumCDMParent.cpp b/dom/media/gmp/ChromiumCDMParent.cpp index 9f1515dc7654..7a54f9af88f4 100644 --- a/dom/media/gmp/ChromiumCDMParent.cpp +++ b/dom/media/gmp/ChromiumCDMParent.cpp @@ -190,7 +190,7 @@ ChromiumCDMParent::InitCDMInputBuffer(gmp::CDMInputBuffer& aBuffer, aBuffer = gmp::CDMInputBuffer(shmem, crypto.mKeyId, crypto.mIV, - aSample->mTime, + aSample->mTime.ToMicroseconds(), aSample->mDuration.ToMicroseconds(), crypto.mPlainSizes, crypto.mEncryptedSizes, @@ -835,7 +835,7 @@ ChromiumCDMParent::DecryptAndDecodeFrame(MediaRawData* aSample) } GMP_LOG("ChromiumCDMParent::DecryptAndDecodeFrame t=%" PRId64, - aSample->mTime); + aSample->mTime.ToMicroseconds()); CDMInputBuffer buffer; diff --git a/dom/media/gtest/TestMP4Demuxer.cpp b/dom/media/gtest/TestMP4Demuxer.cpp index 381e3079c796..9c268bfc10b6 100644 --- a/dom/media/gtest/TestMP4Demuxer.cpp +++ b/dom/media/gtest/TestMP4Demuxer.cpp @@ -63,7 +63,7 @@ public: RefPtr track = aTrackDemuxer; RefPtr binding = this; - int64_t time = -1; + auto time = media::TimeUnit::Invalid(); while (mIndex < mSamples.Length()) { uint32_t i = mIndex++; if (mSamples[i]->mKeyframe) { @@ -74,7 +74,7 @@ public: RefPtr p = mCheckTrackKeyFramePromise.Ensure(__func__); - if (time == -1) { + if (!time.IsValid()) { mCheckTrackKeyFramePromise.Resolve(true, __func__); return p; } @@ -82,7 +82,7 @@ public: DispatchTask( [track, time, binding] () { - track->Seek(media::TimeUnit::FromMicroseconds(time))->Then(binding->mTaskQueue, __func__, + track->Seek(time)->Then(binding->mTaskQueue, __func__, [track, time, binding] () { track->GetSamples()->Then(binding->mTaskQueue, __func__, [track, time, binding] (RefPtr aSamples) { diff --git a/dom/media/ipc/VideoDecoderChild.cpp b/dom/media/ipc/VideoDecoderChild.cpp index b925b322d80d..1abfd586e65d 100644 --- a/dom/media/ipc/VideoDecoderChild.cpp +++ b/dom/media/ipc/VideoDecoderChild.cpp @@ -230,7 +230,7 @@ VideoDecoderChild::Decode(MediaRawData* aSample) memcpy(buffer.get(), aSample->Data(), aSample->Size()); MediaRawDataIPDL sample(MediaDataIPDL(aSample->mOffset, - aSample->mTime, + aSample->mTime.ToMicroseconds(), aSample->mTimecode.ToMicroseconds(), aSample->mDuration.ToMicroseconds(), aSample->mFrames, diff --git a/dom/media/ipc/VideoDecoderParent.cpp b/dom/media/ipc/VideoDecoderParent.cpp index 85372044477a..2d24f0cc389d 100644 --- a/dom/media/ipc/VideoDecoderParent.cpp +++ b/dom/media/ipc/VideoDecoderParent.cpp @@ -137,7 +137,7 @@ VideoDecoderParent::RecvInput(const MediaRawDataIPDL& aData) return IPC_OK(); } data->mOffset = aData.base().offset(); - data->mTime = aData.base().time(); + data->mTime = media::TimeUnit::FromMicroseconds(aData.base().time()); data->mTimecode = media::TimeUnit::FromMicroseconds(aData.base().timecode()); data->mDuration = media::TimeUnit::FromMicroseconds(aData.base().duration()); data->mKeyframe = aData.base().keyframe(); @@ -191,7 +191,8 @@ VideoDecoderParent::ProcessDecodedData( } VideoDataIPDL output( - MediaDataIPDL(data->mOffset, data->mTime, data->mTimecode.ToMicroseconds(), + MediaDataIPDL(data->mOffset, data->mTime.ToMicroseconds(), + data->mTimecode.ToMicroseconds(), data->mDuration.ToMicroseconds(), data->mFrames, data->mKeyframe), video->mDisplay, diff --git a/dom/media/mediasink/AudioSink.cpp b/dom/media/mediasink/AudioSink.cpp index 0f85e294456e..f4c2197e2926 100644 --- a/dom/media/mediasink/AudioSink.cpp +++ b/dom/media/mediasink/AudioSink.cpp @@ -285,7 +285,8 @@ AudioSink::PopFrames(uint32_t aFrames) auto framesToPop = std::min(aFrames, mCursor->Available()); SINK_LOG_V("playing audio at time=%" PRId64 " offset=%u length=%u", - mCurrentData->mTime, mCurrentData->mFrames - mCursor->Available(), framesToPop); + mCurrentData->mTime.ToMicroseconds(), + mCurrentData->mFrames - mCursor->Available(), framesToPop); UniquePtr chunk = MakeUnique(mCurrentData, framesToPop, mCursor->Ptr()); @@ -406,8 +407,8 @@ AudioSink::NotifyAudioNeeded() // audio hardware, so we can play across the gap. // Calculate the timestamp of the next chunk of audio in numbers of // samples. - CheckedInt64 sampleTime = TimeUnitToFrames( - TimeUnit::FromMicroseconds(data->mTime) - mStartTime, data->mRate); + CheckedInt64 sampleTime = + TimeUnitToFrames(data->mTime - mStartTime, data->mRate); // Calculate the number of frames that have been pushed onto the audio hardware. CheckedInt64 missingFrames = sampleTime - mFramesParsed; @@ -501,7 +502,7 @@ AudioSink::CreateAudioFromBuffer(AlignedAudioBuffer&& aBuffer, } RefPtr data = new AudioData(aReference->mOffset, - aReference->mTime, + aReference->mTime.ToMicroseconds(), duration.value(), frames, Move(aBuffer), diff --git a/dom/media/mediasink/DecodedStream.cpp b/dom/media/mediasink/DecodedStream.cpp index 2414e6b34cf1..6060720fe75b 100644 --- a/dom/media/mediasink/DecodedStream.cpp +++ b/dom/media/mediasink/DecodedStream.cpp @@ -461,7 +461,7 @@ SendStreamAudio(DecodedStreamData* aStream, const media::TimeUnit& aStartTime, // the exact same silences CheckedInt64 audioWrittenOffset = aStream->mAudioFramesWritten + TimeUnitToFrames(aStartTime, aRate); - CheckedInt64 frameOffset = UsecsToFrames(audio->mTime, aRate); + CheckedInt64 frameOffset = TimeUnitToFrames(audio->mTime, aRate); if (!audioWrittenOffset.isValid() || !frameOffset.isValid() || @@ -595,7 +595,7 @@ DecodedStream::SendVideo(bool aIsSameOrigin, const PrincipalHandle& aPrincipalHa for (uint32_t i = 0; i < video.Length(); ++i) { VideoData* v = video[i]; - if (mData->mNextVideoTime.ToMicroseconds() < v->mTime) { + if (mData->mNextVideoTime < v->mTime) { // Write last video frame to catch up. mLastVideoImage can be null here // which is fine, it just means there's no video. @@ -605,12 +605,11 @@ DecodedStream::SendVideo(bool aIsSameOrigin, const PrincipalHandle& aPrincipalHa // video frame). E.g. if we have a video frame that is 30 sec long // and capture happens at 15 sec, we'll have to append a black frame // that is 15 sec long. - WriteVideoToMediaStream(sourceStream, mData->mLastVideoImage, - FromMicroseconds(v->mTime), + WriteVideoToMediaStream(sourceStream, mData->mLastVideoImage, v->mTime, mData->mNextVideoTime, mData->mLastVideoImageDisplaySize, - tracksStartTimeStamp + TimeDuration::FromMicroseconds(v->mTime), + tracksStartTimeStamp + v->mTime.ToTimeDuration(), &output, aPrincipalHandle); - mData->mNextVideoTime = FromMicroseconds(v->mTime); + mData->mNextVideoTime = v->mTime; } if (mData->mNextVideoTime < v->GetEndTime()) { @@ -746,7 +745,7 @@ DecodedStream::NotifyOutput(int64_t aTime) { AssertOwnerThread(); mLastOutputTime = FromMicroseconds(aTime); - int64_t currentTime = GetPosition().ToMicroseconds(); + auto currentTime = GetPosition(); // Remove audio samples that have been played by MSG from the queue. RefPtr a = mAudioQueue.PeekFront(); diff --git a/dom/media/mediasink/VideoSink.cpp b/dom/media/mediasink/VideoSink.cpp index 85e6ff9939be..a7656e8153b1 100644 --- a/dom/media/mediasink/VideoSink.cpp +++ b/dom/media/mediasink/VideoSink.cpp @@ -365,8 +365,7 @@ VideoSink::RenderVideoFrames(int32_t aMaxFrames, continue; } - int64_t frameTime = frame->mTime; - if (frameTime < 0) { + if (frame->mTime.IsNegative()) { // Frame times before the start time are invalid; drop such frames continue; } @@ -374,7 +373,7 @@ VideoSink::RenderVideoFrames(int32_t aMaxFrames, TimeStamp t; if (aMaxFrames > 1) { MOZ_ASSERT(!aClockTimeStamp.IsNull()); - int64_t delta = frame->mTime - aClockTime; + int64_t delta = frame->mTime.ToMicroseconds() - aClockTime; t = aClockTimeStamp + TimeDuration::FromMicroseconds(delta / params.mPlaybackRate); if (!lastFrameTime.IsNull() && t <= lastFrameTime) { @@ -394,7 +393,8 @@ VideoSink::RenderVideoFrames(int32_t aMaxFrames, img->mProducerID = mProducerID; VSINK_LOG_V("playing video frame %" PRId64 " (id=%x) (vq-queued=%" PRIuSIZE ")", - frame->mTime, frame->mFrameID, VideoQueue().GetSize()); + frame->mTime.ToMicroseconds(), frame->mFrameID, + VideoQueue().GetSize()); } if (images.Length() > 0) { @@ -424,7 +424,7 @@ VideoSink::UpdateRenderedVideoFrames() } else { mFrameStats.NotifyDecodedFrames({ 0, 0, 1 }); VSINK_LOG_V("discarding video frame mTime=%" PRId64 " clock_time=%" PRId64, - frame->mTime, clockTime.ToMicroseconds()); + frame->mTime.ToMicroseconds(), clockTime.ToMicroseconds()); } } @@ -450,7 +450,7 @@ VideoSink::UpdateRenderedVideoFrames() return; } - int64_t nextFrameTime = frames[1]->mTime; + int64_t nextFrameTime = frames[1]->mTime.ToMicroseconds(); int64_t delta = std::max( nextFrameTime - clockTime.ToMicroseconds(), MIN_UPDATE_INTERVAL_US); TimeStamp target = nowTime + TimeDuration::FromMicroseconds( diff --git a/dom/media/mediasource/MediaSourceDemuxer.cpp b/dom/media/mediasource/MediaSourceDemuxer.cpp index b7ec50affe16..fdfdce9117f6 100644 --- a/dom/media/mediasource/MediaSourceDemuxer.cpp +++ b/dom/media/mediasource/MediaSourceDemuxer.cpp @@ -479,7 +479,7 @@ MediaSourceTrackDemuxer::DoGetSamples(int32_t aNumSamples) } RefPtr samples = new SamplesHolder; samples->mSamples.AppendElement(sample); - if (mNextRandomAccessPoint.ToMicroseconds() <= sample->mTime) { + if (mNextRandomAccessPoint <= sample->mTime) { MonitorAutoLock mon(mMonitor); mNextRandomAccessPoint = mManager->GetNextRandomAccessPoint(mType, MediaSourceDemuxer::EOS_FUZZ); diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index 3e9b28659325..6acf89e1d3d3 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -459,8 +459,8 @@ TrackBuffersManager::DoEvictData(const TimeUnit& aPlaybackTime, MSE_DEBUG("Step1. Evicting %" PRId64 " bytes prior currentTime", aSizeToEvict - toEvict); CodedFrameRemoval( - TimeInterval(TimeUnit::FromMicroseconds(0), - TimeUnit::FromMicroseconds(buffer[lastKeyFrameIndex]->mTime - 1))); + TimeInterval(TimeUnit::Zero(), + buffer[lastKeyFrameIndex]->mTime - TimeUnit::FromMicroseconds(1))); } if (mSizeSourceBuffer <= finalSize) { @@ -487,7 +487,7 @@ TrackBuffersManager::DoEvictData(const TimeUnit& aPlaybackTime, uint32_t evictedFramesStartIndex = buffer.Length(); for (int32_t i = buffer.Length() - 1; i >= 0; i--) { const auto& frame = buffer[i]; - if (frame->mTime <= upperLimit.ToMicroseconds() || toEvict < 0) { + if (frame->mTime <= upperLimit || toEvict < 0) { // We've reached a frame that shouldn't be evicted -> Evict after it -> i+1. // Or the previous loop reached the eviction threshold -> Evict from it -> i+1. evictedFramesStartIndex = i + 1; @@ -499,7 +499,7 @@ TrackBuffersManager::DoEvictData(const TimeUnit& aPlaybackTime, MSE_DEBUG("Step2. Evicting %" PRId64 " bytes from trailing data", mSizeSourceBuffer - finalSize - toEvict); CodedFrameRemoval( - TimeInterval(TimeUnit::FromMicroseconds(buffer[evictedFramesStartIndex]->mTime), + TimeInterval(buffer[evictedFramesStartIndex]->mTime, TimeUnit::FromInfinity())); } } @@ -559,8 +559,8 @@ TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval) // then update remove end timestamp to that random access point timestamp. if (end < track->mBufferedRanges.GetEnd()) { for (auto& frame : track->GetTrackBuffer()) { - if (frame->mKeyframe && frame->mTime >= end.ToMicroseconds()) { - removeEndTimestamp = TimeUnit::FromMicroseconds(frame->mTime); + if (frame->mKeyframe && frame->mTime >= end) { + removeEndTimestamp = frame->mTime; break; } } @@ -1420,14 +1420,12 @@ TimeInterval TrackBuffersManager::PresentationInterval(const TrackBuffer& aSamples) const { TimeInterval presentationInterval = - TimeInterval(TimeUnit::FromMicroseconds(aSamples[0]->mTime), - aSamples[0]->GetEndTime()); + TimeInterval(aSamples[0]->mTime, aSamples[0]->GetEndTime()); for (uint32_t i = 1; i < aSamples.Length(); i++) { auto& sample = aSamples[i]; presentationInterval = presentationInterval.Span( - TimeInterval(TimeUnit::FromMicroseconds(sample->mTime), - sample->GetEndTime())); + TimeInterval(sample->mTime, sample->GetEndTime())); } return presentationInterval; } @@ -1445,8 +1443,8 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData) // Let presentation timestamp be a double precision floating point representation of the coded frame's presentation timestamp in seconds. TimeUnit presentationTimestamp = mSourceBufferAttributes->mGenerateTimestamps - ? TimeUnit() - : TimeUnit::FromMicroseconds(aSamples[0]->mTime); + ? TimeUnit::Zero() + : aSamples[0]->mTime; // 3. If mode equals "sequence" and group start timestamp is set, then run the following steps: CheckSequenceDiscontinuity(presentationTimestamp); @@ -1488,7 +1486,7 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData) SAMPLE_DEBUG("Processing %s frame(pts:%" PRId64 " end:%" PRId64 ", dts:%" PRId64 ", duration:%" PRId64 ", " "kf:%d)", aTrackData.mInfo->mMimeType.get(), - sample->mTime, + sample->mTime.ToMicroseconds(), sample->GetEndTime().ToMicroseconds(), sample->mTimecode.ToMicroseconds(), sample->mDuration.ToMicroseconds(), @@ -1524,7 +1522,7 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData) // Step 3 is performed earlier or when a discontinuity has been detected. // 4. If timestampOffset is not 0, then run the following steps: - TimeUnit sampleTime = TimeUnit::FromMicroseconds(sample->mTime); + TimeUnit sampleTime = sample->mTime; TimeUnit sampleTimecode = sample->mTimecode; TimeUnit sampleDuration = sample->mDuration; TimeUnit timestampOffset = mSourceBufferAttributes->GetTimestampOffset(); @@ -1618,7 +1616,7 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData) samplesRange += sampleInterval; sizeNewSamples += sample->ComputedSizeOfIncludingThis(); - sample->mTime = sampleInterval.mStart.ToMicroseconds(); + sample->mTime = sampleInterval.mStart; sample->mTimecode = decodeTimestamp; sample->mTrackInfo = trackBuffer.mLastInfo; samples.AppendElement(sample); @@ -1694,7 +1692,7 @@ TrackBuffersManager::CheckNextInsertionIndex(TrackData& aTrackData, // We will insert our new frames right before. for (uint32_t i = 0; i < data.Length(); i++) { const RefPtr& sample = data[i]; - if (sample->mTime >= target.mStart.ToMicroseconds() || + if (sample->mTime >= target.mStart || sample->GetEndTime() > target.mStart) { aTrackData.mNextInsertionIndex = Some(i); return true; @@ -1764,8 +1762,7 @@ TrackBuffersManager::InsertFrames(TrackBuffer& aSamples, } // 16. Add the coded frame with the presentation timestamp, decode timestamp, and frame duration to the track buffer. - if (!CheckNextInsertionIndex(aTrackData, - TimeUnit::FromMicroseconds(aSamples[0]->mTime))) { + if (!CheckNextInsertionIndex(aTrackData, aSamples[0]->mTime)) { RejectProcessing(NS_ERROR_FAILURE, __func__); return; } @@ -1837,8 +1834,7 @@ TrackBuffersManager::RemoveFrames(const TimeIntervals& aIntervals, for (uint32_t i = aStartIndex; i < data.Length(); i++) { const RefPtr sample = data[i]; TimeInterval sampleInterval = - TimeInterval(TimeUnit::FromMicroseconds(sample->mTime), - sample->GetEndTime()); + TimeInterval(sample->mTime, sample->GetEndTime()); if (aIntervals.Contains(sampleInterval)) { if (firstRemovedIndex.isNothing()) { firstRemovedIndex = Some(i); @@ -1875,8 +1871,7 @@ TrackBuffersManager::RemoveFrames(const TimeIntervals& aIntervals, for (uint32_t i = firstRemovedIndex.ref(); i <= lastRemovedIndex; i++) { const RefPtr sample = data[i]; TimeInterval sampleInterval = - TimeInterval(TimeUnit::FromMicroseconds(sample->mTime), - sample->GetEndTime()); + TimeInterval(sample->mTime, sample->GetEndTime()); removedIntervals += sampleInterval; if (sample->mDuration > maxSampleDuration) { maxSampleDuration = sample->mDuration; @@ -1938,15 +1933,14 @@ TrackBuffersManager::RemoveFrames(const TimeIntervals& aIntervals, if (aIntervals.GetEnd() >= aTrackData.mHighestStartTimestamp) { // The sample with the highest presentation time got removed. // Rescan the trackbuffer to determine the new one. - int64_t highestStartTime = 0; + TimeUnit highestStartTime; for (const auto& sample : data) { if (sample->mTime > highestStartTime) { highestStartTime = sample->mTime; } } MonitorAutoLock mon(mMonitor); - aTrackData.mHighestStartTimestamp = - TimeUnit::FromMicroseconds(highestStartTime); + aTrackData.mHighestStartTimestamp = highestStartTime; } return firstRemovedIndex.ref(); @@ -2116,7 +2110,7 @@ uint32_t TrackBuffersManager::FindSampleIndex(const TrackBuffer& aTrackBuffer, for (uint32_t i = 0; i < aTrackBuffer.Length(); i++) { const RefPtr& sample = aTrackBuffer[i]; - if (sample->mTime >= target.ToMicroseconds() || + if (sample->mTime >= target || sample->GetEndTime() > target) { return i; } @@ -2165,7 +2159,7 @@ TrackBuffersManager::Seek(TrackInfo::TrackType aTrack, uint32_t lastKeyFrameIndex = 0; for (; i < track.Length(); i++) { const RefPtr& sample = track[i]; - TimeUnit sampleTime = TimeUnit::FromMicroseconds(sample->mTime); + TimeUnit sampleTime = sample->mTime; if (sampleTime > aTime && lastKeyFrameTime.isSome()) { break; } @@ -2238,7 +2232,7 @@ TrackBuffersManager::SkipToNextRandomAccessPoint(TrackInfo::TrackType aTrack, break; } if (sample->mKeyframe && - sample->mTime >= aTimeThreadshold.ToMicroseconds()) { + sample->mTime >= aTimeThreadshold) { aFound = true; break; } @@ -2252,8 +2246,7 @@ TrackBuffersManager::SkipToNextRandomAccessPoint(TrackInfo::TrackType aTrack, // skipped. if (aFound) { trackData.mNextSampleTimecode = track[i]->mTimecode; - trackData.mNextSampleTime = - TimeUnit::FromMicroseconds(track[i]->mTime); + trackData.mNextSampleTime = track[i]->mTime; trackData.mNextGetSampleIndex = Some(i); } else if (i > 0) { // Go back to the previous keyframe or the original position so the next @@ -2262,7 +2255,7 @@ TrackBuffersManager::SkipToNextRandomAccessPoint(TrackInfo::TrackType aTrack, const RefPtr& sample = track[j]; if (sample->mKeyframe) { trackData.mNextSampleTimecode = sample->mTimecode; - trackData.mNextSampleTime = TimeUnit::FromMicroseconds(sample->mTime); + trackData.mNextSampleTime = sample->mTime; trackData.mNextGetSampleIndex = Some(uint32_t(j)); // We are unable to skip to a keyframe past aTimeThreshold, however // we are speeding up decoding by dropping the unplayable frames. @@ -2298,7 +2291,7 @@ TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack, const RefPtr& sample = track[aIndex]; if (!aIndex || sample->mTimecode <= aExpectedDts + aFuzz || - sample->mTime <= (aExpectedPts + aFuzz).ToMicroseconds()) { + sample->mTime <= aExpectedPts + aFuzz) { return sample; } @@ -2366,8 +2359,7 @@ TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack, if (nextSample) { // We have a valid next sample, can use exact values. trackData.mNextSampleTimecode = nextSample->mTimecode; - trackData.mNextSampleTime = - TimeUnit::FromMicroseconds(nextSample->mTime); + trackData.mNextSampleTime = nextSample->mTime; } else { // Next sample isn't available yet. Use estimates. trackData.mNextSampleTimecode = nextSampleTimecode; @@ -2462,7 +2454,7 @@ TrackBuffersManager::FindCurrentPosition(TrackInfo::TrackType aTrack, for (uint32_t i = 0; i < track.Length(); i++) { const RefPtr& sample = track[i]; TimeInterval sampleInterval{ - TimeUnit::FromMicroseconds(sample->mTime), + sample->mTime, sample->GetEndTime(), aFuzz}; @@ -2502,7 +2494,7 @@ TrackBuffersManager::GetNextRandomAccessPoint(TrackInfo::TrackType aTrack, break; } if (sample->mKeyframe) { - return TimeUnit::FromMicroseconds(sample->mTime); + return sample->mTime; } nextSampleTimecode = sample->mTimecode + sample->mDuration; nextSampleTime = sample->GetEndTime(); diff --git a/dom/media/ogg/OggCodecState.cpp b/dom/media/ogg/OggCodecState.cpp index 6d54bd4ae942..f5364c5b71d6 100644 --- a/dom/media/ogg/OggCodecState.cpp +++ b/dom/media/ogg/OggCodecState.cpp @@ -260,7 +260,7 @@ OggCodecState::PacketOutAsMediaRawData() NS_ASSERTION(duration >= 0, "duration invalid"); sample->mTimecode = media::TimeUnit::FromMicroseconds(packet->granulepos); - sample->mTime = end_tstamp - duration; + sample->mTime = media::TimeUnit::FromMicroseconds(end_tstamp - duration); sample->mDuration = media::TimeUnit::FromMicroseconds(duration); sample->mKeyframe = IsKeyframe(packet.get()); sample->mEOS = packet->e_o_s; diff --git a/dom/media/ogg/OggDemuxer.cpp b/dom/media/ogg/OggDemuxer.cpp index fc31362a2efe..9bdfd6854163 100644 --- a/dom/media/ogg/OggDemuxer.cpp +++ b/dom/media/ogg/OggDemuxer.cpp @@ -1317,7 +1317,7 @@ OggTrackDemuxer::Seek(const TimeUnit& aTime) // Check what time we actually seeked to. if (sample != nullptr) { - seekTime = TimeUnit::FromMicroseconds(sample->mTime); + seekTime = sample->mTime; OGG_DEBUG("%p seeked to time %" PRId64, this, seekTime.ToMicroseconds()); } mQueuedSample = sample; @@ -1403,15 +1403,14 @@ OggTrackDemuxer::SkipToNextRandomAccessPoint(const TimeUnit& aTimeThreshold) OGG_DEBUG("TimeThreshold: %f", aTimeThreshold.ToSeconds()); while (!found && (sample = NextSample())) { parsed++; - if (sample->mKeyframe && sample->mTime >= aTimeThreshold.ToMicroseconds()) { + if (sample->mKeyframe && sample->mTime >= aTimeThreshold) { found = true; mQueuedSample = sample; } } if (found) { OGG_DEBUG("next sample: %f (parsed: %d)", - TimeUnit::FromMicroseconds(sample->mTime).ToSeconds(), - parsed); + sample->mTime.ToSeconds(), parsed); return SkipAccessPointPromise::CreateAndResolve(parsed, __func__); } else { SkipFailureHolder failure(NS_ERROR_DOM_MEDIA_END_OF_STREAM, parsed); diff --git a/dom/media/platforms/agnostic/BlankDecoderModule.cpp b/dom/media/platforms/agnostic/BlankDecoderModule.cpp index 688efc8f5335..74edf428e399 100644 --- a/dom/media/platforms/agnostic/BlankDecoderModule.cpp +++ b/dom/media/platforms/agnostic/BlankDecoderModule.cpp @@ -75,11 +75,11 @@ BlankVideoDataCreator::Create(MediaRawData* aSample) return VideoData::CreateAndCopyData(mInfo, mImageContainer, aSample->mOffset, - aSample->mTime, + aSample->mTime.ToMicroseconds(), aSample->mDuration, buffer, aSample->mKeyframe, - aSample->mTime, + aSample->mTime.ToMicroseconds(), mPicture); } @@ -116,7 +116,7 @@ BlankAudioDataCreator::Create(MediaRawData* aSample) mFrameSum++; } RefPtr data(new AudioData(aSample->mOffset, - aSample->mTime, + aSample->mTime.ToMicroseconds(), aSample->mDuration.ToMicroseconds(), uint32_t(frames.value()), Move(samples), diff --git a/dom/media/platforms/agnostic/NullDecoderModule.cpp b/dom/media/platforms/agnostic/NullDecoderModule.cpp index a9a5909b6b79..b10cab2b216a 100644 --- a/dom/media/platforms/agnostic/NullDecoderModule.cpp +++ b/dom/media/platforms/agnostic/NullDecoderModule.cpp @@ -17,7 +17,7 @@ public: // Create a dummy VideoData with no image. This gives us something to // send to media streams if necessary. RefPtr v(new VideoData(aSample->mOffset, - aSample->mTime, + aSample->mTime.ToMicroseconds(), aSample->mDuration.ToMicroseconds(), aSample->mKeyframe, aSample->mTimecode.ToMicroseconds(), diff --git a/dom/media/platforms/agnostic/OpusDecoder.cpp b/dom/media/platforms/agnostic/OpusDecoder.cpp index 8399cbac6261..ce2e05d4c128 100644 --- a/dom/media/platforms/agnostic/OpusDecoder.cpp +++ b/dom/media/platforms/agnostic/OpusDecoder.cpp @@ -167,10 +167,11 @@ OpusDataDecoder::ProcessDecode(MediaRawData* aSample) __func__); } - if (!mLastFrameTime || mLastFrameTime.ref() != aSample->mTime) { + if (!mLastFrameTime || + mLastFrameTime.ref() != aSample->mTime.ToMicroseconds()) { // We are starting a new block. mFrames = 0; - mLastFrameTime = Some(aSample->mTime); + mLastFrameTime = Some(aSample->mTime.ToMicroseconds()); } // Maximum value is 63*2880, so there's no chance of overflow. @@ -231,7 +232,7 @@ OpusDataDecoder::ProcessDecode(MediaRawData* aSample) __func__); } NS_ASSERTION(ret == frames, "Opus decoded too few audio samples"); - CheckedInt64 startTime = aSample->mTime; + CheckedInt64 startTime = aSample->mTime.ToMicroseconds(); // Trim the initial frames while the decoder is settling. if (mSkip > 0) { diff --git a/dom/media/platforms/agnostic/TheoraDecoder.cpp b/dom/media/platforms/agnostic/TheoraDecoder.cpp index c8d4f3b91b0f..7ca44c2f5a87 100644 --- a/dom/media/platforms/agnostic/TheoraDecoder.cpp +++ b/dom/media/platforms/agnostic/TheoraDecoder.cpp @@ -172,7 +172,7 @@ TheoraDecoder::ProcessDecode(MediaRawData* aSample) VideoData::CreateAndCopyData(info, mImageContainer, aSample->mOffset, - aSample->mTime, + aSample->mTime.ToMicroseconds(), aSample->mDuration, b, aSample->mKeyframe, diff --git a/dom/media/platforms/agnostic/VPXDecoder.cpp b/dom/media/platforms/agnostic/VPXDecoder.cpp index 724d5abd40c8..029cccfd0843 100644 --- a/dom/media/platforms/agnostic/VPXDecoder.cpp +++ b/dom/media/platforms/agnostic/VPXDecoder.cpp @@ -207,7 +207,7 @@ VPXDecoder::ProcessDecode(MediaRawData* aSample) v = VideoData::CreateAndCopyData(mInfo, mImageContainer, aSample->mOffset, - aSample->mTime, + aSample->mTime.ToMicroseconds(), aSample->mDuration, b, aSample->mKeyframe, @@ -224,7 +224,7 @@ VPXDecoder::ProcessDecode(MediaRawData* aSample) v = VideoData::CreateAndCopyData(mInfo, mImageContainer, aSample->mOffset, - aSample->mTime, + aSample->mTime.ToMicroseconds(), aSample->mDuration, b, alpha_plane, diff --git a/dom/media/platforms/agnostic/VorbisDecoder.cpp b/dom/media/platforms/agnostic/VorbisDecoder.cpp index 517261217d79..4f0702f4686f 100644 --- a/dom/media/platforms/agnostic/VorbisDecoder.cpp +++ b/dom/media/platforms/agnostic/VorbisDecoder.cpp @@ -141,15 +141,16 @@ VorbisDataDecoder::ProcessDecode(MediaRawData* aSample) const unsigned char* aData = aSample->Data(); size_t aLength = aSample->Size(); int64_t aOffset = aSample->mOffset; - int64_t aTstampUsecs = aSample->mTime; + int64_t aTstampUsecs = aSample->mTime.ToMicroseconds(); int64_t aTotalFrames = 0; MOZ_ASSERT(mPacketCount >= 3); - if (!mLastFrameTime || mLastFrameTime.ref() != aSample->mTime) { + if (!mLastFrameTime || + mLastFrameTime.ref() != aSample->mTime.ToMicroseconds()) { // We are starting a new block. mFrames = 0; - mLastFrameTime = Some(aSample->mTime); + mLastFrameTime = Some(aSample->mTime.ToMicroseconds()); } ogg_packet pkt = InitVorbisPacket( diff --git a/dom/media/platforms/agnostic/WAVDecoder.cpp b/dom/media/platforms/agnostic/WAVDecoder.cpp index 204b82f1a9e4..e0258256d2bf 100644 --- a/dom/media/platforms/agnostic/WAVDecoder.cpp +++ b/dom/media/platforms/agnostic/WAVDecoder.cpp @@ -79,7 +79,7 @@ WaveDataDecoder::ProcessDecode(MediaRawData* aSample) size_t aLength = aSample->Size(); ByteReader aReader(aSample->Data(), aLength); int64_t aOffset = aSample->mOffset; - uint64_t aTstampUsecs = aSample->mTime; + uint64_t aTstampUsecs = aSample->mTime.ToMicroseconds(); int32_t frames = aLength * 8 / mInfo.mBitDepth / mInfo.mChannels; diff --git a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp index 8c76dbeaeb86..53620e0d4c9c 100644 --- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp +++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp @@ -200,7 +200,7 @@ GMPVideoDecoder::CreateFrame(MediaRawData* aSample) frame->SetEncodedWidth(mConfig.mDisplay.width); frame->SetEncodedHeight(mConfig.mDisplay.height); - frame->SetTimeStamp(aSample->mTime); + frame->SetTimeStamp(aSample->mTime.ToMicroseconds()); frame->SetCompleteFrame(true); frame->SetDuration(aSample->mDuration.ToMicroseconds()); frame->SetFrameType(aSample->mKeyframe ? kGMPKeyFrame : kGMPDeltaFrame); diff --git a/dom/media/platforms/android/RemoteDataDecoder.cpp b/dom/media/platforms/android/RemoteDataDecoder.cpp index 33b234519eaf..1480add2c180 100644 --- a/dom/media/platforms/android/RemoteDataDecoder.cpp +++ b/dom/media/platforms/android/RemoteDataDecoder.cpp @@ -226,7 +226,7 @@ public: InputInfo info( aSample->mDuration.ToMicroseconds(), config->mImage, config->mDisplay); - mInputInfos.Insert(aSample->mTime, info); + mInputInfos.Insert(aSample->mTime.ToMicroseconds(), info); return RemoteDataDecoder::Decode(aSample); } @@ -537,7 +537,7 @@ RemoteDataDecoder::Decode(MediaRawData* aSample) return DecodePromise::CreateAndReject( MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__), __func__); } - bufferInfo->Set(0, sample->Size(), sample->mTime, 0); + bufferInfo->Set(0, sample->Size(), sample->mTime.ToMicroseconds(), 0); mDrainStatus = DrainStatus::DRAINABLE; return mJavaDecoder->Input(bytes, bufferInfo, GetCryptoInfoFromSample(sample)) diff --git a/dom/media/platforms/apple/AppleATDecoder.cpp b/dom/media/platforms/apple/AppleATDecoder.cpp index 33e61488388a..4862d2fc8143 100644 --- a/dom/media/platforms/apple/AppleATDecoder.cpp +++ b/dom/media/platforms/apple/AppleATDecoder.cpp @@ -67,7 +67,7 @@ RefPtr AppleATDecoder::Decode(MediaRawData* aSample) { LOG("mp4 input sample %p %lld us %lld pts%s %llu bytes audio", aSample, - aSample->mDuration.ToMicroseconds(), aSample->mTime, + aSample->mDuration.ToMicroseconds(), aSample->mTime.ToMicroseconds(), aSample->mKeyframe ? " keyframe" : "", (unsigned long long)aSample->Size()); RefPtr self = this; @@ -270,7 +270,7 @@ AppleATDecoder::DecodeSample(MediaRawData* aSample) LOG("Error decoding audio sample: %d\n", static_cast(rv)); return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, RESULT_DETAIL("Error decoding audio sample: %d @ %lld", - static_cast(rv), aSample->mTime)); + static_cast(rv), aSample->mTime.ToMicroseconds())); } if (numFrames) { @@ -323,7 +323,7 @@ AppleATDecoder::DecodeSample(MediaRawData* aSample) } RefPtr audio = new AudioData(aSample->mOffset, - aSample->mTime, + aSample->mTime.ToMicroseconds(), duration.ToMicroseconds(), numFrames, data.Forget(), diff --git a/dom/media/platforms/apple/AppleVTDecoder.cpp b/dom/media/platforms/apple/AppleVTDecoder.cpp index 7ca6f20c8958..275c132d87d2 100644 --- a/dom/media/platforms/apple/AppleVTDecoder.cpp +++ b/dom/media/platforms/apple/AppleVTDecoder.cpp @@ -78,7 +78,7 @@ AppleVTDecoder::Decode(MediaRawData* aSample) { LOG("mp4 input sample %p pts %lld duration %lld us%s %" PRIuSIZE " bytes", aSample, - aSample->mTime, + aSample->mTime.ToMicroseconds(), aSample->mDuration.ToMicroseconds(), aSample->mKeyframe ? " keyframe" : "", aSample->Size()); @@ -132,7 +132,7 @@ TimingInfoFromSample(MediaRawData* aSample) timestamp.duration = CMTimeMake( aSample->mDuration.ToMicroseconds(), USECS_PER_S); timestamp.presentationTimeStamp = - CMTimeMake(aSample->mTime, USECS_PER_S); + CMTimeMake(aSample->mTime.ToMicroseconds(), USECS_PER_S); timestamp.decodeTimeStamp = CMTimeMake(aSample->mTimecode.ToMicroseconds(), USECS_PER_S); diff --git a/dom/media/platforms/apple/AppleVTDecoder.h b/dom/media/platforms/apple/AppleVTDecoder.h index 168077404e38..ee4f4c11c840 100644 --- a/dom/media/platforms/apple/AppleVTDecoder.h +++ b/dom/media/platforms/apple/AppleVTDecoder.h @@ -33,7 +33,7 @@ public: explicit AppleFrameRef(const MediaRawData& aSample) : decode_timestamp(aSample.mTimecode) - , composition_timestamp(media::TimeUnit::FromMicroseconds(aSample.mTime)) + , composition_timestamp(aSample.mTime) , duration(aSample.mDuration) , byte_offset(aSample.mOffset) , is_sync_point(aSample.mKeyframe) diff --git a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp index 4336b657f593..b1f623927967 100644 --- a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp @@ -137,7 +137,7 @@ FFmpegAudioDecoder::ProcessDecode(MediaRawData* aSample) } int64_t samplePosition = aSample->mOffset; - media::TimeUnit pts = media::TimeUnit::FromMicroseconds(aSample->mTime); + media::TimeUnit pts = aSample->mTime; DecodedData results; while (packet.size > 0) { diff --git a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp index 518fa024e61c..9a01fefa3bbd 100644 --- a/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp @@ -197,7 +197,8 @@ FFmpegVideoDecoder::DoDecode(MediaRawData* aSample, bool* aGotFrame, int size; int len = mLib->av_parser_parse2( mCodecParser, mCodecContext, &data, &size, inputData, inputSize, - aSample->mTime, aSample->mTimecode.ToMicroseconds(), aSample->mOffset); + aSample->mTime.ToMicroseconds(), aSample->mTimecode.ToMicroseconds(), + aSample->mOffset); if (size_t(len) > inputSize) { return NS_ERROR_DOM_MEDIA_DECODE_ERR; } @@ -232,7 +233,7 @@ FFmpegVideoDecoder::DoDecode(MediaRawData* aSample, packet.data = aData; packet.size = aSize; packet.dts = mLastInputDts = aSample->mTimecode.ToMicroseconds(); - packet.pts = aSample->mTime; + packet.pts = aSample->mTime.ToMicroseconds(); packet.flags = aSample->mKeyframe ? AV_PKT_FLAG_KEY : 0; packet.pos = aSample->mOffset; diff --git a/dom/media/platforms/omx/OmxDataDecoder.cpp b/dom/media/platforms/omx/OmxDataDecoder.cpp index c273c688be75..80b5edfeb260 100644 --- a/dom/media/platforms/omx/OmxDataDecoder.cpp +++ b/dom/media/platforms/omx/OmxDataDecoder.cpp @@ -445,7 +445,7 @@ OmxDataDecoder::FillAndEmptyBuffers() inbuf->mBuffer->nOffset = 0; inbuf->mBuffer->nFlags = inbuf->mBuffer->nAllocLen > data->Size() ? OMX_BUFFERFLAG_ENDOFFRAME : 0; - inbuf->mBuffer->nTimeStamp = data->mTime; + inbuf->mBuffer->nTimeStamp = data->mTime.ToMicroseconds(); if (data->Size()) { inbuf->mRawData = mMediaRawDatas[0]; } else { diff --git a/dom/media/platforms/omx/OmxPromiseLayer.cpp b/dom/media/platforms/omx/OmxPromiseLayer.cpp index 943d59d7dafd..f13867c9d02a 100644 --- a/dom/media/platforms/omx/OmxPromiseLayer.cpp +++ b/dom/media/platforms/omx/OmxPromiseLayer.cpp @@ -123,7 +123,7 @@ already_AddRefed OmxPromiseLayer::FindAndRemoveRawData(OMX_TICKS aTimecode) { for (auto raw : mRawDatas) { - if (raw->mTime == aTimecode) { + if (raw->mTime.ToMicroseconds() == aTimecode) { mRawDatas.RemoveElement(raw); return raw.forget(); } diff --git a/dom/media/platforms/wmf/WMFAudioMFTManager.cpp b/dom/media/platforms/wmf/WMFAudioMFTManager.cpp index 8d52d0cd94f5..78ca54035e63 100644 --- a/dom/media/platforms/wmf/WMFAudioMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFAudioMFTManager.cpp @@ -193,7 +193,7 @@ WMFAudioMFTManager::Input(MediaRawData* aSample) { return mDecoder->Input(aSample->Data(), uint32_t(aSample->Size()), - aSample->mTime); + aSample->mTime.ToMicroseconds()); } HRESULT diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp index e9371c43aeb0..b096d4de20bc 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp @@ -668,12 +668,12 @@ WMFVideoMFTManager::Input(MediaRawData* aSample) RefPtr inputSample; HRESULT hr = mDecoder->CreateInputSample(aSample->Data(), uint32_t(aSample->Size()), - aSample->mTime, + aSample->mTime.ToMicroseconds(), &inputSample); NS_ENSURE_TRUE(SUCCEEDED(hr) && inputSample != nullptr, hr); mLastDuration = aSample->mDuration.ToMicroseconds(); - mLastTime = aSample->mTime; + mLastTime = aSample->mTime.ToMicroseconds(); mSamplesCount++; // Forward sample data to the decoder. @@ -1032,7 +1032,7 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset, aOutData = frame; // Set the potentially corrected pts and duration. - aOutData->mTime = pts.ToMicroseconds(); + aOutData->mTime = pts; aOutData->mDuration = duration; if (mNullOutputCount) { diff --git a/dom/media/wave/WaveDemuxer.cpp b/dom/media/wave/WaveDemuxer.cpp index 7c0923e2b31f..ac3cba6eb713 100644 --- a/dom/media/wave/WaveDemuxer.cpp +++ b/dom/media/wave/WaveDemuxer.cpp @@ -531,7 +531,7 @@ WAVTrackDemuxer::GetNextChunk(const MediaByteRange& aRange) ++mNumParsedChunks; ++mChunkIndex; - datachunk->mTime = Duration(mChunkIndex - 1).ToMicroseconds(); + datachunk->mTime = Duration(mChunkIndex - 1); if (static_cast(mChunkIndex) * DATA_CHUNK_SIZE < mDataLength) { datachunk->mDuration = Duration(1); @@ -540,10 +540,10 @@ WAVTrackDemuxer::GetNextChunk(const MediaByteRange& aRange) mDataLength - mChunkIndex * DATA_CHUNK_SIZE; datachunk->mDuration = DurationFromBytes(mBytesRemaining); } - datachunk->mTimecode = media::TimeUnit::FromMicroseconds(datachunk->mTime); + datachunk->mTimecode = datachunk->mTime; datachunk->mKeyframe = true; - MOZ_ASSERT(datachunk->mTime >= 0); + MOZ_ASSERT(!datachunk->mTime.IsNegative()); MOZ_ASSERT(!datachunk->mDuration.IsNegative()); return datachunk.forget(); diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index 9e0bf56e8cec..63b6c9b95a52 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -723,7 +723,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, } } sample->mTimecode = media::TimeUnit::FromMicroseconds(tstamp); - sample->mTime = tstamp; + sample->mTime = media::TimeUnit::FromMicroseconds(tstamp); sample->mDuration = media::TimeUnit::FromMicroseconds(next_tstamp - tstamp); sample->mOffset = holder->Offset(); sample->mKeyframe = isKeyframe; @@ -1082,7 +1082,7 @@ WebMTrackDemuxer::Seek(const media::TimeUnit& aTime) // Check what time we actually seeked to. if (mSamples.GetSize() > 0) { const RefPtr& sample = mSamples.First(); - seekTime = media::TimeUnit::FromMicroseconds(sample->mTime); + seekTime = sample->mTime; } SetNextKeyFrameTime(); @@ -1140,7 +1140,7 @@ WebMTrackDemuxer::SetNextKeyFrameTime() return; } - int64_t frameTime = -1; + auto frameTime = media::TimeUnit::Invalid(); mNextKeyframeTime.reset(); @@ -1181,8 +1181,8 @@ WebMTrackDemuxer::SetNextKeyFrameTime() // in the right order. mSamples.PushFront(Move(skipSamplesQueue)); - if (frameTime != -1) { - mNextKeyframeTime.emplace(media::TimeUnit::FromMicroseconds(frameTime)); + if (frameTime.IsValid()) { + mNextKeyframeTime.emplace(frameTime); WEBM_DEBUG("Next Keyframe %f (%u queued %.02fs)", mNextKeyframeTime.value().ToSeconds(), uint32_t(mSamples.GetSize()), @@ -1220,8 +1220,7 @@ WebMTrackDemuxer::UpdateSamples(nsTArray>& aSamples) } } if (mNextKeyframeTime.isNothing() - || aSamples.LastElement()->mTime - >= mNextKeyframeTime.value().ToMicroseconds()) { + || aSamples.LastElement()->mTime >= mNextKeyframeTime.value()) { SetNextKeyFrameTime(); } } @@ -1247,13 +1246,13 @@ WebMTrackDemuxer::SkipToNextRandomAccessPoint( bool found = false; RefPtr sample; nsresult rv = NS_OK; - int64_t sampleTime; WEBM_DEBUG("TimeThreshold: %f", aTimeThreshold.ToSeconds()); while (!found && NS_SUCCEEDED((rv = NextSample(sample)))) { parsed++; - sampleTime = sample->mTime; - if (sample->mKeyframe && sampleTime >= aTimeThreshold.ToMicroseconds()) { + if (sample->mKeyframe && sample->mTime >= aTimeThreshold) { + WEBM_DEBUG("next sample: %f (parsed: %d)", + sample->mTime.ToSeconds(), parsed); found = true; mSamples.Reset(); mSamples.PushFront(sample.forget()); @@ -1263,9 +1262,6 @@ WebMTrackDemuxer::SkipToNextRandomAccessPoint( SetNextKeyFrameTime(); } if (found) { - WEBM_DEBUG("next sample: %f (parsed: %d)", - media::TimeUnit::FromMicroseconds(sampleTime).ToSeconds(), - parsed); return SkipAccessPointPromise::CreateAndResolve(parsed, __func__); } else { SkipFailureHolder failure(NS_ERROR_DOM_MEDIA_END_OF_STREAM, parsed); diff --git a/media/libstagefright/binding/Index.cpp b/media/libstagefright/binding/Index.cpp index 73d5be405a2a..910373b03ec0 100644 --- a/media/libstagefright/binding/Index.cpp +++ b/media/libstagefright/binding/Index.cpp @@ -101,7 +101,7 @@ already_AddRefed SampleIterator::GetNext() RefPtr sample = new MediaRawData(); sample->mTimecode= TimeUnit::FromMicroseconds(s->mDecodeTime); - sample->mTime = s->mCompositionRange.start; + sample->mTime = TimeUnit::FromMicroseconds(s->mCompositionRange.start); sample->mDuration = TimeUnit::FromMicroseconds(s->mCompositionRange.Length()); sample->mOffset = s->mByteRange.mStart; sample->mKeyframe = s->mSync; From 884b33eca61af16748f1a4a4cc07ec97b368d8f2 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 20 Apr 2017 04:27:33 -0500 Subject: [PATCH 45/65] servo: Merge #16511 - Implement -webkit-radial-gradient() (fixes #15441) (from nox:webkit-gradients); r=emilio Source-Repo: https://github.com/servo/servo Source-Revision: 7f825d2119a480a64b103e1d60a2d469af98d3de --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 117fc2f36804a6f9498add63c7556eba82b55409 --- servo/components/style/gecko/conversions.rs | 24 +-- .../style/values/specified/image.rs | 158 ++++++++++++------ 2 files changed, 121 insertions(+), 61 deletions(-) diff --git a/servo/components/style/gecko/conversions.rs b/servo/components/style/gecko/conversions.rs index 3531f35b9b25..0a14a5c34104 100644 --- a/servo/components/style/gecko/conversions.rs +++ b/servo/components/style/gecko/conversions.rs @@ -207,16 +207,21 @@ impl nsStyleImage { gecko_gradient }, GradientKind::Radial(shape, position) => { + let keyword_to_gecko_size = |keyword| { + match keyword { + SizeKeyword::ClosestSide => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, + SizeKeyword::FarthestSide => NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE, + SizeKeyword::ClosestCorner => NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER, + SizeKeyword::FarthestCorner => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER, + SizeKeyword::Contain => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, + SizeKeyword::Cover => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER, + } + }; let (gecko_shape, gecko_size) = match shape { GradientShape::Circle(ref length) => { let size = match *length { LengthOrKeyword::Keyword(keyword) => { - match keyword { - SizeKeyword::ClosestSide => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, - SizeKeyword::FarthestSide => NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE, - SizeKeyword::ClosestCorner => NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER, - SizeKeyword::FarthestCorner => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER, - } + keyword_to_gecko_size(keyword) }, _ => NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE, }; @@ -225,12 +230,7 @@ impl nsStyleImage { GradientShape::Ellipse(ref length) => { let size = match *length { LengthOrPercentageOrKeyword::Keyword(keyword) => { - match keyword { - SizeKeyword::ClosestSide => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, - SizeKeyword::FarthestSide => NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE, - SizeKeyword::ClosestCorner => NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER, - SizeKeyword::FarthestCorner => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER, - } + keyword_to_gecko_size(keyword) }, _ => NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE, }; diff --git a/servo/components/style/values/specified/image.rs b/servo/components/style/values/specified/image.rs index 50129350c63f..0604b059263b 100644 --- a/servo/components/style/values/specified/image.rs +++ b/servo/components/style/values/specified/image.rs @@ -121,9 +121,15 @@ impl ToCss for Gradient { }, GradientKind::Radial(ref shape, ref position) => { try!(dest.write_str("radial-gradient(")); - try!(shape.to_css(dest)); - try!(dest.write_str(" at ")); - try!(position.to_css(dest)); + if self.compat_mode == CompatMode::Modern { + try!(shape.to_css(dest)); + try!(dest.write_str(" at ")); + try!(position.to_css(dest)); + } else { + try!(position.to_css(dest)); + try!(dest.write_str(", ")); + try!(shape.to_css(dest)); + } }, } for stop in &self.stops { @@ -148,9 +154,16 @@ impl Gradient { Ok((kind, stops)) }) }; - let parse_radial_gradient = |input: &mut Parser| { + let parse_modern_radial_gradient = |input: &mut Parser| { input.parse_nested_block(|input| { - let kind = try!(GradientKind::parse_radial(context, input)); + let kind = try!(GradientKind::parse_modern_radial(context, input)); + let stops = try!(input.parse_comma_separated(|i| ColorStop::parse(context, i))); + Ok((kind, stops)) + }) + }; + let parse_webkit_radial_gradient = |input: &mut Parser| { + input.parse_nested_block(|input| { + let kind = try!(GradientKind::parse_webkit_radial(context, input)); let stops = try!(input.parse_comma_separated(|i| ColorStop::parse(context, i))); Ok((kind, stops)) }) @@ -175,11 +188,20 @@ impl Gradient { try!(parse_linear_gradient(input, compat_mode)) }, "radial-gradient" => { - try!(parse_radial_gradient(input)) + try!(parse_modern_radial_gradient(input)) + }, + "-webkit-radial-gradient" => { + compat_mode = CompatMode::WebKit; + try!(parse_webkit_radial_gradient(input)) }, "repeating-radial-gradient" => { repeating = true; - try!(parse_radial_gradient(input)) + try!(parse_modern_radial_gradient(input)) + }, + "-webkit-repeating-radial-gradient" => { + repeating = true; + compat_mode = CompatMode::WebKit; + try!(parse_webkit_radial_gradient(input)) }, _ => { return Err(()); } }; @@ -231,53 +253,21 @@ impl GradientKind { Ok(GradientKind::Linear(angle_or_corner)) } - /// Parses a radial gradient from the given arguments. - pub fn parse_radial(context: &ParserContext, input: &mut Parser) -> Result { + /// Parses a modern radial gradient from the given arguments. + pub fn parse_modern_radial(context: &ParserContext, input: &mut Parser) -> Result { let mut needs_comma = true; - // Ending shape and position can be in various order. Checks all probabilities. let (shape, position) = if let Ok(position) = input.try(|i| parse_position(context, i)) { - // Handle just + // Handle just "at" (EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::FarthestCorner)), position) - } else if let Ok((first, second)) = input.try(|i| parse_two_length(context, i)) { - // Handle ? ? - let _ = input.try(|input| input.expect_ident_matching("ellipse")); - (EndingShape::Ellipse(LengthOrPercentageOrKeyword::LengthOrPercentage(first, second)), - input.try(|i| parse_position(context, i)).unwrap_or(Position::center())) - } else if let Ok(length) = input.try(|i| Length::parse(context, i)) { - // Handle ? ? - let _ = input.try(|input| input.expect_ident_matching("circle")); - (EndingShape::Circle(LengthOrKeyword::Length(length)), - input.try(|i| parse_position(context, i)).unwrap_or(Position::center())) - } else if let Ok(keyword) = input.try(SizeKeyword::parse) { - // Handle ? ? - let shape = if input.try(|input| input.expect_ident_matching("circle")).is_ok() { - EndingShape::Circle(LengthOrKeyword::Keyword(keyword)) - } else { - let _ = input.try(|input| input.expect_ident_matching("ellipse")); - EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(keyword)) - }; + } else if let Ok(shape) = input.try(|i| parse_shape(context, i, SizeKeyword::parse_modern)) { + // Handle ["at" ]? (shape, input.try(|i| parse_position(context, i)).unwrap_or(Position::center())) } else { - // Handle ? ? - if input.try(|input| input.expect_ident_matching("ellipse")).is_ok() { - // Handle ? ? - let length = input.try(|i| LengthOrPercentageOrKeyword::parse(context, i)) - .unwrap_or(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::FarthestCorner)); - (EndingShape::Ellipse(length), - input.try(|i| parse_position(context, i)).unwrap_or(Position::center())) - } else if input.try(|input| input.expect_ident_matching("circle")).is_ok() { - // Handle ? ? - let length = input.try(|i| LengthOrKeyword::parse(context, i)) - .unwrap_or(LengthOrKeyword::Keyword(SizeKeyword::FarthestCorner)); - (EndingShape::Circle(length), input.try(|i| parse_position(context, i)) - .unwrap_or(Position::center())) - } else { - // If there is no shape keyword, it should set to default. - needs_comma = false; - (EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::FarthestCorner)), - input.try(|i| parse_position(context, i)).unwrap_or(Position::center())) - } + // If there is no shape keyword, it should set to default. + needs_comma = false; + (EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::FarthestCorner)), + Position::center()) }; if needs_comma { @@ -286,6 +276,26 @@ impl GradientKind { Ok(GradientKind::Radial(shape, position)) } + + /// Parses a webkit radial gradient from the given arguments. + /// https://compat.spec.whatwg.org/#css-gradients-webkit-radial-gradient + pub fn parse_webkit_radial(context: &ParserContext, input: &mut Parser) -> Result { + let position = if let Ok(position) = input.try(|i| Position::parse(context, i)) { + try!(input.expect_comma()); + position + } else { + Position::center() + }; + + let shape = if let Ok(shape) = input.try(|i| parse_shape(context, i, SizeKeyword::parse)) { + try!(input.expect_comma()); + shape + } else { + EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::Cover)) + }; + + Ok(GradientKind::Radial(shape, position)) + } } /// Specified values for `moz-image-rect` @@ -358,6 +368,46 @@ fn parse_position(context: &ParserContext, input: &mut Parser) -> Result(context: &ParserContext, + input: &mut Parser, + parse_size_keyword: F) + -> Result + where F: FnOnce(&mut Parser) -> Result +{ + if let Ok((first, second)) = input.try(|i| parse_two_length(context, i)) { + // Handle ? + let _ = input.try(|input| input.expect_ident_matching("ellipse")); + Ok(EndingShape::Ellipse(LengthOrPercentageOrKeyword::LengthOrPercentage(first, second))) + } else if let Ok(length) = input.try(|i| Length::parse(context, i)) { + // Handle ? + let _ = input.try(|input| input.expect_ident_matching("circle")); + Ok(EndingShape::Circle(LengthOrKeyword::Length(length))) + } else if let Ok(keyword) = input.try(parse_size_keyword) { + // Handle ? + if input.try(|input| input.expect_ident_matching("circle")).is_ok() { + Ok(EndingShape::Circle(LengthOrKeyword::Keyword(keyword))) + } else { + let _ = input.try(|input| input.expect_ident_matching("ellipse")); + Ok(EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(keyword))) + } + } else { + // https://github.com/rust-lang/rust/issues/41272 + if input.try(|input| input.expect_ident_matching("ellipse")).is_ok() { + // Handle ? + let length = input.try(|i| LengthOrPercentageOrKeyword::parse(context, i)) + .unwrap_or(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::FarthestCorner)); + Ok(EndingShape::Ellipse(length)) + } else if input.try(|input| input.expect_ident_matching("circle")).is_ok() { + // Handle ? + let length = input.try(|i| LengthOrKeyword::parse(context, i)) + .unwrap_or(LengthOrKeyword::Keyword(SizeKeyword::FarthestCorner)); + Ok(EndingShape::Circle(length)) + } else { + Err(()) + } + } +} + /// Specified values for an angle or a corner in a linear gradient. #[derive(Clone, PartialEq, Copy, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] @@ -545,4 +595,14 @@ impl ToCss for LengthOrPercentageOrKeyword { /// https://drafts.csswg.org/css-images/#typedef-extent-keyword define_css_keyword_enum!(SizeKeyword: "closest-side" => ClosestSide, "farthest-side" => FarthestSide, - "closest-corner" => ClosestCorner, "farthest-corner" => FarthestCorner); + "closest-corner" => ClosestCorner, "farthest-corner" => FarthestCorner, + "contain" => Contain, "cover" => Cover); + +impl SizeKeyword { + fn parse_modern(input: &mut Parser) -> Result { + match try!(SizeKeyword::parse(input)) { + SizeKeyword::Contain | SizeKeyword::Cover => Err(()), + keyword => Ok(keyword), + } + } +} From 45f1ae7b2ac6b1d817833a1b640c8591b12c2bba Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 20 Apr 2017 05:19:37 -0500 Subject: [PATCH 46/65] servo: Merge #16513 - Properly parse background-size in background longhand (fixes #15199) (from nox:background-slash-size); r=upsuper Source-Repo: https://github.com/servo/servo Source-Revision: 26fd65995dcaa543437ccfddb0f2693b6505e9f0 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : fc50268623a664b8da13c77214056cce37f7eeee --- .../style/properties/longhand/background.mako.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/servo/components/style/properties/longhand/background.mako.rs b/servo/components/style/properties/longhand/background.mako.rs index 1b33d7dd0be5..994f70a0a25c 100644 --- a/servo/components/style/properties/longhand/background.mako.rs +++ b/servo/components/style/properties/longhand/background.mako.rs @@ -494,11 +494,9 @@ ${helpers.single_keyword("background-origin", let width = try!(specified::LengthOrPercentageOrAuto::parse_non_negative(context, input)); - let height = if input.is_exhausted() { - specified::LengthOrPercentageOrAuto::Auto - } else { - try!(specified::LengthOrPercentageOrAuto::parse_non_negative(context, input)) - }; + let height = input.try(|input| { + specified::LengthOrPercentageOrAuto::parse_non_negative(context, input) + }).unwrap_or(specified::LengthOrPercentageOrAuto::Auto); Ok(SpecifiedValue::Explicit(ExplicitSize { width: width, From 0367a0da9ff334c00bc81b35e04409c06ff92a3c Mon Sep 17 00:00:00 2001 From: Johann Hofmann Date: Thu, 20 Apr 2017 12:56:26 +0200 Subject: [PATCH 47/65] Bug 1358083 - Rename browser/themes/shared/toolbarbuttons.inc.css to toolbarbutton-icons.inc.css. r=dao MozReview-Commit-ID: 2jY3sq5k62y --HG-- rename : browser/themes/shared/toolbarbuttons.inc.css => browser/themes/shared/toolbarbutton-icons.inc.css extra : rebase_source : c253f549f95ebcb72b125b0d3ee72700048129a3 --- browser/themes/linux/browser.css | 2 +- browser/themes/osx/browser.css | 2 +- .../{toolbarbuttons.inc.css => toolbarbutton-icons.inc.css} | 0 browser/themes/windows/browser.css | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename browser/themes/shared/{toolbarbuttons.inc.css => toolbarbutton-icons.inc.css} (100%) diff --git a/browser/themes/linux/browser.css b/browser/themes/linux/browser.css index 96ef068973cd..3b20bf8fe323 100644 --- a/browser/themes/linux/browser.css +++ b/browser/themes/linux/browser.css @@ -553,7 +553,7 @@ menuitem.bookmark-item { /* Menu panel buttons */ -%include ../shared/toolbarbuttons.inc.css +%include ../shared/toolbarbutton-icons.inc.css %include ../shared/menupanel.inc.css #main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-icon, diff --git a/browser/themes/osx/browser.css b/browser/themes/osx/browser.css index 9df293fd0858..f3ff4c816a68 100644 --- a/browser/themes/osx/browser.css +++ b/browser/themes/osx/browser.css @@ -726,7 +726,7 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic -moz-box-align: center; } -%include ../shared/toolbarbuttons.inc.css +%include ../shared/toolbarbutton-icons.inc.css %include ../shared/menupanel.inc.css @media not all and (min-resolution: 1.1dppx) { diff --git a/browser/themes/shared/toolbarbuttons.inc.css b/browser/themes/shared/toolbarbutton-icons.inc.css similarity index 100% rename from browser/themes/shared/toolbarbuttons.inc.css rename to browser/themes/shared/toolbarbutton-icons.inc.css diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css index a853c686ccfa..2592105dbad0 100644 --- a/browser/themes/windows/browser.css +++ b/browser/themes/windows/browser.css @@ -578,7 +578,7 @@ menuitem.bookmark-item { /* ::::: primary toolbar buttons ::::: */ -%include ../shared/toolbarbuttons.inc.css +%include ../shared/toolbarbutton-icons.inc.css #main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-icon, #main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menu-dropmarker, From eb02505b4cf149088cb583e38f0ab4d6085a781c Mon Sep 17 00:00:00 2001 From: nchevobbe Date: Thu, 20 Apr 2017 10:43:32 +0200 Subject: [PATCH 48/65] Bug 1357341 - Reps 0.6.0: update reps bundle from Github; r=jdescottes MozReview-Commit-ID: BW0DPLf8dXf --HG-- extra : rebase_source : b674cd7b3bb493abe1130485b4e3b388b11fdec6 --- .../client/shared/components/reps/reps.js | 3133 ++++++++--------- .../components/reps/test/mochitest/head.js | 4 - .../reps/test/mochitest/test_reps_array.html | 12 +- .../test/mochitest/test_reps_attribute.html | 10 +- .../mochitest/test_reps_comment-node.html | 12 +- .../test/mochitest/test_reps_date-time.html | 12 +- .../test/mochitest/test_reps_document.html | 12 +- .../mochitest/test_reps_element-node.html | 85 +- .../reps/test/mochitest/test_reps_error.html | 57 +- .../reps/test/mochitest/test_reps_event.html | 32 +- .../test/mochitest/test_reps_failure.html | 10 +- .../test/mochitest/test_reps_function.html | 11 +- .../test/mochitest/test_reps_grip-array.html | 114 +- .../test/mochitest/test_reps_grip-map.html | 122 +- .../reps/test/mochitest/test_reps_grip.html | 113 +- .../test/mochitest/test_reps_infinity.html | 15 +- .../test/mochitest/test_reps_long-string.html | 12 +- .../reps/test/mochitest/test_reps_nan.html | 11 +- .../reps/test/mochitest/test_reps_null.html | 10 +- .../reps/test/mochitest/test_reps_number.html | 16 +- .../mochitest/test_reps_object-with-text.html | 10 +- .../mochitest/test_reps_object-with-url.html | 10 +- .../reps/test/mochitest/test_reps_object.html | 11 +- .../test/mochitest/test_reps_promise.html | 84 +- .../reps/test/mochitest/test_reps_regexp.html | 10 +- .../reps/test/mochitest/test_reps_string.html | 19 +- .../test/mochitest/test_reps_stylesheet.html | 10 +- .../reps/test/mochitest/test_reps_symbol.html | 16 +- .../test/mochitest/test_reps_text-node.html | 36 +- .../test/mochitest/test_reps_undefined.html | 10 +- .../reps/test/mochitest/test_reps_window.html | 11 +- 31 files changed, 1987 insertions(+), 2043 deletions(-) diff --git a/devtools/client/shared/components/reps/reps.js b/devtools/client/shared/components/reps/reps.js index bb32e0128630..0b0dfcf831cd 100644 --- a/devtools/client/shared/components/reps/reps.js +++ b/devtools/client/shared/components/reps/reps.js @@ -7,7 +7,7 @@ var a = typeof exports === 'object' ? factory(require("devtools/client/shared/vendor/react")) : factory(root["devtools/client/shared/vendor/react"]); for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; } -})(this, function(__WEBPACK_EXTERNAL_MODULE_3__) { +})(this, function(__WEBPACK_EXTERNAL_MODULE_4__) { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; @@ -55,17 +55,18 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { const { MODE } = __webpack_require__(1); - const { REPS } = __webpack_require__(2); + const { REPS, getRep } = __webpack_require__(2); const { createFactories, parseURLEncodedText, parseURLParams, getSelectableInInspectorGrips, maybeEscapePropertyName - } = __webpack_require__(4); + } = __webpack_require__(3); module.exports = { REPS, + getRep, MODE, createFactories, maybeEscapePropertyName, @@ -90,10 +91,7 @@ return /******/ (function(modules) { // webpackBootstrap /* 2 */ /***/ function(module, exports, __webpack_require__) { - const React = __webpack_require__(3); - - const { isGrip } = __webpack_require__(4); - const { MODE } = __webpack_require__(1); + const { isGrip } = __webpack_require__(3); // Load all existing rep templates const Undefined = __webpack_require__(6); @@ -138,21 +136,14 @@ return /******/ (function(modules) { // webpackBootstrap * to the current value type. The value must be passed is as 'object' * property. */ - const Rep = React.createClass({ - displayName: "Rep", - - propTypes: { - object: React.PropTypes.any, - defaultRep: React.PropTypes.object, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])) - }, - - render: function () { - let rep = getRep(this.props.object, this.props.defaultRep); - return rep(this.props); - } - }); + const Rep = function (props) { + let { + object, + defaultRep + } = props; + let rep = getRep(object, defaultRep); + return rep(props); + }; // Helpers @@ -186,14 +177,14 @@ return /******/ (function(modules) { // webpackBootstrap // but a number), which would allow to priorities templates and // support better extensibility. if (rep.supportsObject(object, type)) { - return React.createFactory(rep.rep); + return rep.rep; } } catch (err) { console.error(err); } } - return React.createFactory(defaultRep.rep); + return defaultRep.rep; } module.exports = { @@ -228,21 +219,17 @@ return /******/ (function(modules) { // webpackBootstrap TextNode, Undefined, Window - } + }, + // Exporting for tests + getRep }; /***/ }, /* 3 */ -/***/ function(module, exports) { - - module.exports = __WEBPACK_EXTERNAL_MODULE_3__; - -/***/ }, -/* 4 */ /***/ function(module, exports, __webpack_require__) { // Dependencies - const React = __webpack_require__(3); + const React = __webpack_require__(4); // Utils const nodeConstants = __webpack_require__(5); @@ -321,12 +308,17 @@ return /******/ (function(modules) { // webpackBootstrap * * @param {String} str * the input + * @param {Boolean} escapeWhitespace + * if true, TAB, CR, and NL characters will be escaped * @return {String} the escaped string */ - function escapeString(str) { + function escapeString(str, escapeWhitespace) { return "\"" + str.replace(escapeRegexp, (match, offset) => { let c = match.charCodeAt(0); if (c in escapeMap) { + if (!escapeWhitespace && (c === 9 || c === 0xa || c === 0xd)) { + return match[0]; + } return escapeMap[c]; } if (c >= 0xd800 && c <= 0xdfff) { @@ -495,10 +487,11 @@ return /******/ (function(modules) { // webpackBootstrap * fallback rep if the render fails. */ function wrapRender(renderMethod) { - return function () { + const wrappedFunction = function (props) { try { - return renderMethod.call(this); + return renderMethod.call(this, props); } catch (e) { + console.error(e); return React.DOM.span({ className: "objectBox objectBox-failure", title: "This object could not be rendered, " + "please file a bug on bugzilla.mozilla.org" @@ -507,6 +500,8 @@ return /******/ (function(modules) { // webpackBootstrap "Invalid object"); } }; + wrappedFunction.propTypes = renderMethod.propTypes; + return wrappedFunction; } /** @@ -599,6 +594,36 @@ return /******/ (function(modules) { // webpackBootstrap return []; } + /** + * Returns a new element wrapped with a component, props.objectLink if it exists, + * or a span if there are multiple childs, or directly the child if only one is passed. + * + * @param {Object} props A Rep "props" object that may contain `objectLink` + * and `object` properties. + * @param {Object} config Object to pass as props to the `objectLink` component. + * @param {...Element} children Elements to be wrapped with the `objectLink` component. + * @return {Element} Element, wrapped or not, depending if `objectLink` + * was supplied in props. + */ + function safeObjectLink(props, config, ...children) { + const { + objectLink, + object + } = props; + + if (objectLink) { + return objectLink(Object.assign({ + object + }, config), ...children); + } + + if ((!config || Object.keys(config).length === 0) && children.length === 1) { + return children[0]; + } + + return React.DOM.span(config, ...children); + } + module.exports = { createFactories, isGrip, @@ -613,9 +638,16 @@ return /******/ (function(modules) { // webpackBootstrap getFileName, getURLDisplayString, getSelectableInInspectorGrips, - maybeEscapePropertyName + maybeEscapePropertyName, + safeObjectLink }; +/***/ }, +/* 4 */ +/***/ function(module, exports) { + + module.exports = __WEBPACK_EXTERNAL_MODULE_4__; + /***/ }, /* 5 */ /***/ function(module, exports) { @@ -648,9 +680,9 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // Dependencies - const React = __webpack_require__(3); + const React = __webpack_require__(4); - const { wrapRender } = __webpack_require__(4); + const { wrapRender } = __webpack_require__(3); // Shortcuts const { span } = React.DOM; @@ -658,13 +690,9 @@ return /******/ (function(modules) { // webpackBootstrap /** * Renders undefined value */ - const Undefined = React.createClass({ - displayName: "UndefinedRep", - - render: wrapRender(function () { - return span({ className: "objectBox objectBox-undefined" }, "undefined"); - }) - }); + const Undefined = function () { + return span({ className: "objectBox objectBox-undefined" }, "undefined"); + }; function supportsObject(object, type) { if (object && object.type && object.type == "undefined") { @@ -677,8 +705,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: Undefined, - supportsObject: supportsObject + rep: wrapRender(Undefined), + supportsObject }; /***/ }, @@ -686,9 +714,9 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // Dependencies - const React = __webpack_require__(3); + const React = __webpack_require__(4); - const { wrapRender } = __webpack_require__(4); + const { wrapRender } = __webpack_require__(3); // Shortcuts const { span } = React.DOM; @@ -696,13 +724,9 @@ return /******/ (function(modules) { // webpackBootstrap /** * Renders null value */ - const Null = React.createClass({ - displayName: "NullRep", - - render: wrapRender(function () { - return span({ className: "objectBox objectBox-null" }, "null"); - }) - }); + function Null(props) { + return span({ className: "objectBox objectBox-null" }, "null"); + } function supportsObject(object, type) { if (object && object.type && object.type == "null") { @@ -715,8 +739,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: Null, - supportsObject: supportsObject + rep: wrapRender(Null), + supportsObject }; /***/ }, @@ -724,14 +748,14 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // Dependencies - const React = __webpack_require__(3); + const React = __webpack_require__(4); const { escapeString, rawCropString, sanitizeString, wrapRender - } = __webpack_require__(4); + } = __webpack_require__(3); // Shortcuts const { span } = React.DOM; @@ -739,46 +763,42 @@ return /******/ (function(modules) { // webpackBootstrap /** * Renders a string. String value is enclosed within quotes. */ - const StringRep = React.createClass({ - displayName: "StringRep", + StringRep.propTypes = { + useQuotes: React.PropTypes.bool, + escapeWhitespace: React.PropTypes.bool, + style: React.PropTypes.object, + object: React.PropTypes.string.isRequired, + member: React.PropTypes.any, + cropLimit: React.PropTypes.number + }; - propTypes: { - useQuotes: React.PropTypes.bool, - style: React.PropTypes.object, - object: React.PropTypes.string.isRequired, - member: React.PropTypes.any, - cropLimit: React.PropTypes.number - }, + function StringRep(props) { + let { + cropLimit, + object: text, + member, + style, + useQuotes = true, + escapeWhitespace = true + } = props; - getDefaultProps: function () { - return { - useQuotes: true - }; - }, + let config = { className: "objectBox objectBox-string" }; + if (style) { + config.style = style; + } - render: wrapRender(function () { - let text = this.props.object; - let member = this.props.member; - let style = this.props.style; + if (useQuotes) { + text = escapeString(text, escapeWhitespace); + } else { + text = sanitizeString(text); + } - let config = { className: "objectBox objectBox-string" }; - if (style) { - config.style = style; - } + if ((!member || !member.open) && cropLimit) { + text = rawCropString(text, cropLimit); + } - if (this.props.useQuotes) { - text = escapeString(text); - } else { - text = sanitizeString(text); - } - - if ((!member || !member.open) && this.props.cropLimit) { - text = rawCropString(text, this.props.cropLimit); - } - - return span(config, text); - }) - }); + return span(config, text); + } function supportsObject(object, type) { return type == "string"; @@ -787,8 +807,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: StringRep, - supportsObject: supportsObject + rep: wrapRender(StringRep), + supportsObject }; /***/ }, @@ -796,60 +816,52 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // Dependencies - const React = __webpack_require__(3); + const React = __webpack_require__(4); const { escapeString, sanitizeString, isGrip, wrapRender - } = __webpack_require__(4); + } = __webpack_require__(3); // Shortcuts const { span } = React.DOM; /** * Renders a long string grip. */ - const LongStringRep = React.createClass({ - displayName: "LongStringRep", + LongStringRep.propTypes = { + useQuotes: React.PropTypes.bool, + escapeWhitespace: React.PropTypes.bool, + style: React.PropTypes.object, + cropLimit: React.PropTypes.number.isRequired, + member: React.PropTypes.string, + object: React.PropTypes.object.isRequired + }; - propTypes: { - useQuotes: React.PropTypes.bool, - style: React.PropTypes.object, - cropLimit: React.PropTypes.number.isRequired, - member: React.PropTypes.string, - object: React.PropTypes.object.isRequired - }, + function LongStringRep(props) { + let { + cropLimit, + member, + object, + style, + useQuotes = true, + escapeWhitespace = true + } = props; + let { fullText, initial, length } = object; - getDefaultProps: function () { - return { - useQuotes: true - }; - }, + let config = { className: "objectBox objectBox-string" }; + if (style) { + config.style = style; + } - render: wrapRender(function () { - let { - cropLimit, - member, - object, - style, - useQuotes - } = this.props; - let { fullText, initial, length } = object; + let string = member && member.open ? fullText || initial : initial.substring(0, cropLimit); - let config = { className: "objectBox objectBox-string" }; - if (style) { - config.style = style; - } - - let string = member && member.open ? fullText || initial : initial.substring(0, cropLimit); - - if (string.length < length) { - string += "\u2026"; - } - let formattedString = useQuotes ? escapeString(string) : sanitizeString(string); - return span(config, formattedString); - }) - }); + if (string.length < length) { + string += "\u2026"; + } + let formattedString = useQuotes ? escapeString(string, escapeWhitespace) : sanitizeString(string); + return span(config, formattedString); + } function supportsObject(object, type) { if (!isGrip(object)) { @@ -860,8 +872,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: LongStringRep, - supportsObject: supportsObject + rep: wrapRender(LongStringRep), + supportsObject }; /***/ }, @@ -869,9 +881,9 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // Dependencies - const React = __webpack_require__(3); + const React = __webpack_require__(4); - const { wrapRender } = __webpack_require__(4); + const { wrapRender } = __webpack_require__(3); // Shortcuts const { span } = React.DOM; @@ -879,25 +891,21 @@ return /******/ (function(modules) { // webpackBootstrap /** * Renders a number */ - const Number = React.createClass({ - displayName: "Number", + Number.propTypes = { + object: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.number, React.PropTypes.bool]).isRequired + }; - propTypes: { - object: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.number, React.PropTypes.bool]).isRequired - }, + function Number(props) { + let value = props.object; - stringify: function (object) { - let isNegativeZero = Object.is(object, -0) || object.type && object.type == "-0"; + return span({ className: "objectBox objectBox-number" }, stringify(value)); + } - return isNegativeZero ? "-0" : String(object); - }, + function stringify(object) { + let isNegativeZero = Object.is(object, -0) || object.type && object.type == "-0"; - render: wrapRender(function () { - let value = this.props.object; - - return span({ className: "objectBox objectBox-number" }, this.stringify(value)); - }) - }); + return isNegativeZero ? "-0" : String(object); + } function supportsObject(object, type) { return ["boolean", "number", "-0"].includes(type); @@ -906,8 +914,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: Number, - supportsObject: supportsObject + rep: wrapRender(Number), + supportsObject }; /***/ }, @@ -915,12 +923,12 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // Dependencies - const React = __webpack_require__(3); + const React = __webpack_require__(4); const { - createFactories, + safeObjectLink, wrapRender - } = __webpack_require__(4); - const Caption = React.createFactory(__webpack_require__(12)); + } = __webpack_require__(3); + const Caption = __webpack_require__(12); const { MODE } = __webpack_require__(1); const ModePropType = React.PropTypes.oneOf( @@ -934,169 +942,101 @@ return /******/ (function(modules) { // webpackBootstrap * Renders an array. The array is enclosed by left and right bracket * and the max number of rendered items depends on the current mode. */ - let ArrayRep = React.createClass({ - displayName: "ArrayRep", + ArrayRep.propTypes = { + mode: ModePropType, + objectLink: React.PropTypes.func, + object: React.PropTypes.array.isRequired + }; - propTypes: { - mode: ModePropType, - objectLink: React.PropTypes.func, - object: React.PropTypes.array.isRequired - }, + function ArrayRep(props) { + let { + object, + mode = MODE.SHORT + } = props; - getTitle: function (object, context) { - return "[" + object.length + "]"; - }, + let items; + let brackets; + let needSpace = function (space) { + return space ? { left: "[ ", right: " ]" } : { left: "[", right: "]" }; + }; - arrayIterator: function (array, max) { - let items = []; - let delim; + if (mode === MODE.TINY) { + let isEmpty = object.length === 0; + items = [DOM.span({ className: "length" }, isEmpty ? "" : object.length)]; + brackets = needSpace(false); + } else { + let max = mode === MODE.SHORT ? 3 : 10; + items = arrayIterator(props, object, max); + brackets = needSpace(items.length > 0); + } - for (let i = 0; i < array.length && i < max; i++) { - try { - let value = array[i]; + return DOM.span({ + className: "objectBox objectBox-array" }, safeObjectLink(props, { + className: "arrayLeftBracket", + object: object + }, brackets.left), ...items, safeObjectLink(props, { + className: "arrayRightBracket", + object: object + }, brackets.right), DOM.span({ + className: "arrayProperties", + role: "group" })); + } - delim = i == array.length - 1 ? "" : ", "; + function arrayIterator(props, array, max) { + let items = []; + let delim; - items.push(ItemRep({ - object: value, - // Hardcode tiny mode to avoid recursive handling. - mode: MODE.TINY, - delim: delim - })); - } catch (exc) { - items.push(ItemRep({ - object: exc, - mode: MODE.TINY, - delim: delim - })); - } - } + for (let i = 0; i < array.length && i < max; i++) { + try { + let value = array[i]; - if (array.length > max) { - items.push(Caption({ - object: this.safeObjectLink({ - object: this.props.object - }, array.length - max + " more…") + delim = i == array.length - 1 ? "" : ", "; + + items.push(ItemRep({ + object: value, + // Hardcode tiny mode to avoid recursive handling. + mode: MODE.TINY, + delim: delim + })); + } catch (exc) { + items.push(ItemRep({ + object: exc, + mode: MODE.TINY, + delim: delim })); } + } - return items; - }, + if (array.length > max) { + items.push(Caption({ + object: safeObjectLink(props, { + object: props.object + }, array.length - max + " more…") + })); + } - /** - * Returns true if the passed object is an array with additional (custom) - * properties, otherwise returns false. Custom properties should be - * displayed in extra expandable section. - * - * Example array with a custom property. - * let arr = [0, 1]; - * arr.myProp = "Hello"; - * - * @param {Array} array The array object. - */ - hasSpecialProperties: function (array) { - function isInteger(x) { - let y = parseInt(x, 10); - if (isNaN(y)) { - return false; - } - return x === y.toString(); - } - - let propsArray = Object.getOwnPropertyNames(array); - for (let i = 0; i < propsArray.length; i++) { - let p = propsArray[i]; - - // Valid indexes are skipped - if (isInteger(p)) { - continue; - } - - // Ignore standard 'length' property, anything else is custom. - if (p != "length") { - return true; - } - } - - return false; - }, - - // Event Handlers - - onToggleProperties: function (event) {}, - - onClickBracket: function (event) {}, - - safeObjectLink: function (config, ...children) { - if (this.props.objectLink) { - return this.props.objectLink(Object.assign({ - object: this.props.object - }, config), ...children); - } - - if (Object.keys(config).length === 0 && children.length === 1) { - return children[0]; - } - - return DOM.span(config, ...children); - }, - - render: wrapRender(function () { - let { - object, - mode = MODE.SHORT - } = this.props; - - let items; - let brackets; - let needSpace = function (space) { - return space ? { left: "[ ", right: " ]" } : { left: "[", right: "]" }; - }; - - if (mode === MODE.TINY) { - let isEmpty = object.length === 0; - items = [DOM.span({ className: "length" }, isEmpty ? "" : object.length)]; - brackets = needSpace(false); - } else { - let max = mode === MODE.SHORT ? 3 : 10; - items = this.arrayIterator(object, max); - brackets = needSpace(items.length > 0); - } - - return DOM.span({ - className: "objectBox objectBox-array" }, this.safeObjectLink({ - className: "arrayLeftBracket", - object: object - }, brackets.left), ...items, this.safeObjectLink({ - className: "arrayRightBracket", - object: object - }, brackets.right), DOM.span({ - className: "arrayProperties", - role: "group" })); - }) - }); + return items; + } /** * Renders array item. Individual values are separated by a comma. */ - let ItemRep = React.createFactory(React.createClass({ - displayName: "ItemRep", + ItemRep.propTypes = { + object: React.PropTypes.any.isRequired, + delim: React.PropTypes.string.isRequired, + mode: ModePropType + }; - propTypes: { - object: React.PropTypes.any.isRequired, - delim: React.PropTypes.string.isRequired, - mode: ModePropType - }, + function ItemRep(props) { + const { Rep } = __webpack_require__(2); - render: wrapRender(function () { - const { Rep } = createFactories(__webpack_require__(2)); - - let object = this.props.object; - let delim = this.props.delim; - let mode = this.props.mode; - return DOM.span({}, Rep({ object: object, mode: mode }), delim); - }) - })); + let { + object, + delim, + mode + } = props; + return DOM.span({}, Rep({ object: object, mode: mode }), delim); + } function supportsObject(object, type) { return Array.isArray(object) || Object.prototype.toString.call(object) === "[object Arguments]"; @@ -1104,8 +1044,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: ArrayRep, - supportsObject: supportsObject + rep: wrapRender(ArrayRep), + supportsObject }; /***/ }, @@ -1113,41 +1053,38 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // Dependencies - const React = __webpack_require__(3); + const React = __webpack_require__(4); const DOM = React.DOM; - const { wrapRender } = __webpack_require__(4); + const { wrapRender } = __webpack_require__(3); /** * Renders a caption. This template is used by other components * that needs to distinguish between a simple text/value and a label. */ - const Caption = React.createClass({ - displayName: "Caption", + Caption.propTypes = { + object: React.PropTypes.oneOfType([React.PropTypes.number, React.PropTypes.string]).isRequired + }; - propTypes: { - object: React.PropTypes.oneOfType([React.PropTypes.number, React.PropTypes.string]).isRequired - }, - - render: wrapRender(function () { - return DOM.span({ "className": "caption" }, this.props.object); - }) - }); + function Caption(props) { + return DOM.span({ "className": "caption" }, props.object); + } // Exports from this module - module.exports = Caption; + module.exports = wrapRender(Caption); /***/ }, /* 13 */ /***/ function(module, exports, __webpack_require__) { // Dependencies - const React = __webpack_require__(3); + const React = __webpack_require__(4); const { + safeObjectLink, wrapRender - } = __webpack_require__(4); - const Caption = React.createFactory(__webpack_require__(12)); - const PropRep = React.createFactory(__webpack_require__(14)); + } = __webpack_require__(3); + const Caption = __webpack_require__(12); + const PropRep = __webpack_require__(14); const { MODE } = __webpack_require__(1); // Shortcuts const { span } = React.DOM; @@ -1155,152 +1092,146 @@ return /******/ (function(modules) { // webpackBootstrap * Renders an object. An object is represented by a list of its * properties enclosed in curly brackets. */ - const Obj = React.createClass({ - displayName: "Obj", + ObjectRep.propTypes = { + object: React.PropTypes.object.isRequired, + // @TODO Change this to Object.values once it's supported in Node's version of V8 + mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + objectLink: React.PropTypes.func, + title: React.PropTypes.string + }; - propTypes: { - object: React.PropTypes.object.isRequired, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - objectLink: React.PropTypes.func, - title: React.PropTypes.string - }, + function ObjectRep(props) { + let object = props.object; + let propsArray = safePropIterator(props, object); - getTitle: function (object) { - let title = this.props.title || object.class || "Object"; - return this.safeObjectLink({ className: "objectTitle" }, title); - }, + if (props.mode === MODE.TINY || !propsArray.length) { + return span({ className: "objectBox objectBox-object" }, getTitle(props, object)); + } - safePropIterator: function (object, max) { - max = typeof max === "undefined" ? 3 : max; - try { - return this.propIterator(object, max); - } catch (err) { - console.error(err); - } - return []; - }, + return span({ className: "objectBox objectBox-object" }, getTitle(props, object), safeObjectLink(props, { + className: "objectLeftBrace" + }, " { "), ...propsArray, safeObjectLink(props, { + className: "objectRightBrace" + }, " }")); + } - propIterator: function (object, max) { - let isInterestingProp = (t, value) => { - // Do not pick objects, it could cause recursion. - return t == "boolean" || t == "number" || t == "string" && value; - }; + function getTitle(props, object) { + let title = props.title || object.class || "Object"; + return safeObjectLink(props, { className: "objectTitle" }, title); + } - // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=945377 - if (Object.prototype.toString.call(object) === "[object Generator]") { - object = Object.getPrototypeOf(object); - } + function safePropIterator(props, object, max) { + max = typeof max === "undefined" ? 3 : max; + try { + return propIterator(props, object, max); + } catch (err) { + console.error(err); + } + return []; + } - // Object members with non-empty values are preferred since it gives the - // user a better overview of the object. - let propsArray = this.getPropsArray(object, max, isInterestingProp); + function propIterator(props, object, max) { + let isInterestingProp = (type, value) => { + // Do not pick objects, it could cause recursion. + return type == "boolean" || type == "number" || type == "string" && value; + }; - if (propsArray.length <= max) { - // There are not enough props yet (or at least, not enough props to - // be able to know whether we should print "more…" or not). - // Let's display also empty members and functions. - propsArray = propsArray.concat(this.getPropsArray(object, max, (t, value) => { - return !isInterestingProp(t, value); - })); - } + // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=945377 + if (Object.prototype.toString.call(object) === "[object Generator]") { + object = Object.getPrototypeOf(object); + } - if (propsArray.length > max) { - propsArray.pop(); - let objectLink = this.props.objectLink || span; + // Object members with non-empty values are preferred since it gives the + // user a better overview of the object. + let interestingObject = getFilteredObject(object, max, isInterestingProp); - propsArray.push(Caption({ - object: objectLink({ - object: object - }, Object.keys(object).length - max + " more…") - })); - } else if (propsArray.length > 0) { - // Remove the last comma. - propsArray[propsArray.length - 1] = React.cloneElement(propsArray[propsArray.length - 1], { delim: "" }); - } + if (Object.keys(interestingObject).length < max) { + // There are not enough props yet (or at least, not enough props to + // be able to know whether we should print "more…" or not). + // Let's display also empty members and functions. + interestingObject = Object.assign({}, interestingObject, getFilteredObject(object, max - Object.keys(interestingObject).length, (type, value) => !isInterestingProp(type, value))); + } + const truncated = Object.keys(object).length > max; + let propsArray = getPropsArray(interestingObject, truncated); + if (truncated) { + propsArray.push(Caption({ + object: safeObjectLink(props, {}, Object.keys(object).length - max + " more…") + })); + } + + return propsArray; + } + + /** + * Get an array of components representing the properties of the object + * + * @param {Object} object + * @param {Boolean} truncated true if the object is truncated. + * @return {Array} Array of PropRep. + */ + function getPropsArray(object, truncated) { + let propsArray = []; + + if (!object) { return propsArray; - }, + } - getPropsArray: function (object, max, filter) { - let propsArray = []; + // Hardcode tiny mode to avoid recursive handling. + let mode = MODE.TINY; + const objectKeys = Object.keys(object); + return objectKeys.map((name, i) => PropRep({ + mode, + name, + object: object[name], + equal: ": ", + delim: i !== objectKeys.length - 1 || truncated ? ", " : null + })); + } - max = max || 3; - if (!object) { - return propsArray; - } + /** + * Get a copy of the object filtered by a given predicate. + * + * @param {Object} object. + * @param {Number} max The maximum length of keys array. + * @param {Function} filter Filter the props you want. + * @return {Object} the filtered object. + */ + function getFilteredObject(object, max, filter) { + let filteredObject = {}; - // Hardcode tiny mode to avoid recursive handling. - let mode = MODE.TINY; - - try { - for (let name in object) { - if (propsArray.length > max) { - return propsArray; - } - - let value; - try { - value = object[name]; - } catch (exc) { - continue; - } - - let t = typeof value; - if (filter(t, value)) { - propsArray.push(PropRep({ - mode: mode, - name: name, - object: value, - equal: ": ", - delim: ", " - })); - } + try { + for (let name in object) { + if (Object.keys(filteredObject).length >= max) { + return filteredObject; + } + + let value; + try { + value = object[name]; + } catch (exc) { + continue; + } + + let t = typeof value; + if (filter(t, value)) { + filteredObject[name] = value; } - } catch (err) { - console.error(err); } + } catch (err) { + console.error(err); + } + return filteredObject; + } - return propsArray; - }, - - safeObjectLink: function (config, ...children) { - if (this.props.objectLink) { - return this.props.objectLink(Object.assign({ - object: this.props.object - }, config), ...children); - } - - if (Object.keys(config).length === 0 && children.length === 1) { - return children[0]; - } - - return span(config, ...children); - }, - - render: wrapRender(function () { - let object = this.props.object; - let propsArray = this.safePropIterator(object); - - if (this.props.mode === MODE.TINY || !propsArray.length) { - return span({ className: "objectBox objectBox-object" }, this.getTitle(object)); - } - - return span({ className: "objectBox objectBox-object" }, this.getTitle(object), this.safeObjectLink({ - className: "objectLeftBrace" - }, " { "), ...propsArray, this.safeObjectLink({ - className: "objectRightBrace" - }, " }")); - }) - }); function supportsObject(object, type) { return true; } // Exports from this module module.exports = { - rep: Obj, - supportsObject: supportsObject + rep: wrapRender(ObjectRep), + supportsObject }; /***/ }, @@ -1308,12 +1239,11 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // Dependencies - const React = __webpack_require__(3); + const React = __webpack_require__(4); const { - createFactories, maybeEscapePropertyName, wrapRender - } = __webpack_require__(4); + } = __webpack_require__(3); const { MODE } = __webpack_require__(1); // Shortcuts const { span } = React.DOM; @@ -1323,81 +1253,82 @@ return /******/ (function(modules) { // webpackBootstrap * and GripMap (remote JS maps and weakmaps) reps. * It's used to render object properties. */ - let PropRep = React.createClass({ - displayName: "PropRep", + PropRep.propTypes = { + // Property name. + name: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.object]).isRequired, + // Equal character rendered between property name and value. + equal: React.PropTypes.string, + // Delimiter character used to separate individual properties. + delim: React.PropTypes.string, + // @TODO Change this to Object.values once it's supported in Node's version of V8 + mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + objectLink: React.PropTypes.func, + onDOMNodeMouseOver: React.PropTypes.func, + onDOMNodeMouseOut: React.PropTypes.func, + onInspectIconClick: React.PropTypes.func, + // Normally a PropRep will quote a property name that isn't valid + // when unquoted; but this flag can be used to suppress the + // quoting. + suppressQuotes: React.PropTypes.bool + }; - propTypes: { - // Property name. - name: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.object]).isRequired, - // Equal character rendered between property name and value. - equal: React.PropTypes.string, - // Delimiter character used to separate individual properties. - delim: React.PropTypes.string, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - objectLink: React.PropTypes.func, - attachedActorIds: React.PropTypes.array, - onDOMNodeMouseOver: React.PropTypes.func, - onDOMNodeMouseOut: React.PropTypes.func, - onInspectIconClick: React.PropTypes.func, - // Normally a PropRep will quote a property name that isn't valid - // when unquoted; but this flag can be used to suppress the - // quoting. - suppressQuotes: React.PropTypes.bool - }, + function PropRep(props) { + const Grip = __webpack_require__(15); + const { Rep } = __webpack_require__(2); - render: wrapRender(function () { - const Grip = __webpack_require__(15); - let { Rep } = createFactories(__webpack_require__(2)); - let { - name, - mode, - equal, - delim, - suppressQuotes - } = this.props; + let { + name, + mode, + equal, + delim, + suppressQuotes + } = props; - let key; - // The key can be a simple string, for plain objects, - // or another object for maps and weakmaps. - if (typeof name === "string") { - if (!suppressQuotes) { - name = maybeEscapePropertyName(name); - } - key = span({ "className": "nodeName" }, name); - } else { - key = Rep(Object.assign({}, this.props, { - object: name, - mode: mode || MODE.TINY, - defaultRep: Grip - })); + let key; + // The key can be a simple string, for plain objects, + // or another object for maps and weakmaps. + if (typeof name === "string") { + if (!suppressQuotes) { + name = maybeEscapePropertyName(name); } + key = span({ "className": "nodeName" }, name); + } else { + key = Rep(Object.assign({}, props, { + object: name, + mode: mode || MODE.TINY, + defaultRep: Grip + })); + } - return span({}, key, span({ - "className": "objectEqual" - }, equal), Rep(Object.assign({}, this.props)), span({ + let delimElement; + if (delim) { + delimElement = span({ "className": "objectComma" - }, delim)); - }) - }); + }, delim); + } + + return span({}, key, span({ + "className": "objectEqual" + }, equal), Rep(Object.assign({}, props)), delimElement); + } // Exports from this module - module.exports = PropRep; + module.exports = wrapRender(PropRep); /***/ }, /* 15 */ /***/ function(module, exports, __webpack_require__) { // ReactJS - const React = __webpack_require__(3); + const React = __webpack_require__(4); // Dependencies const { - createFactories, isGrip, + safeObjectLink, wrapRender - } = __webpack_require__(4); - const Caption = React.createFactory(__webpack_require__(12)); - const PropRep = React.createFactory(__webpack_require__(14)); + } = __webpack_require__(3); + const Caption = __webpack_require__(12); + const PropRep = __webpack_require__(14); const { MODE } = __webpack_require__(1); // Shortcuts const { span } = React.DOM; @@ -1407,209 +1338,187 @@ return /******/ (function(modules) { // webpackBootstrap * of remote JS object and is used as an input object * for this rep component. */ - const GripRep = React.createClass({ - displayName: "Grip", + GripRep.propTypes = { + object: React.PropTypes.object.isRequired, + // @TODO Change this to Object.values once it's supported in Node's version of V8 + mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + isInterestingProp: React.PropTypes.func, + title: React.PropTypes.string, + objectLink: React.PropTypes.func, + onDOMNodeMouseOver: React.PropTypes.func, + onDOMNodeMouseOut: React.PropTypes.func, + onInspectIconClick: React.PropTypes.func + }; - propTypes: { - object: React.PropTypes.object.isRequired, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - isInterestingProp: React.PropTypes.func, - title: React.PropTypes.string, - objectLink: React.PropTypes.func, - attachedActorIds: React.PropTypes.array, - onDOMNodeMouseOver: React.PropTypes.func, - onDOMNodeMouseOut: React.PropTypes.func, - onInspectIconClick: React.PropTypes.func - }, + function GripRep(props) { + let object = props.object; + let propsArray = safePropIterator(props, object, props.mode === MODE.LONG ? 10 : 3); - getTitle: function (object) { - let title = this.props.title || object.class || "Object"; - return this.safeObjectLink({}, title); - }, + if (props.mode === MODE.TINY) { + return span({ className: "objectBox objectBox-object" }, getTitle(props, object)); + } - safePropIterator: function (object, max) { - max = typeof max === "undefined" ? 3 : max; - try { - return this.propIterator(object, max); - } catch (err) { - console.error(err); - } - return []; - }, + return span({ className: "objectBox objectBox-object" }, getTitle(props, object), safeObjectLink(props, { + className: "objectLeftBrace" + }, " { "), ...propsArray, safeObjectLink(props, { + className: "objectRightBrace" + }, " }")); + } - propIterator: function (object, max) { - if (object.preview && Object.keys(object.preview).includes("wrappedValue")) { - const { Rep } = createFactories(__webpack_require__(2)); + function getTitle(props, object) { + let title = props.title || object.class || "Object"; + return safeObjectLink(props, {}, title); + } - return [Rep({ - object: object.preview.wrappedValue, - mode: this.props.mode || MODE.TINY, - defaultRep: Grip - })]; - } + function safePropIterator(props, object, max) { + max = typeof max === "undefined" ? 3 : max; + try { + return propIterator(props, object, max); + } catch (err) { + console.error(err); + } + return []; + } - // Property filter. Show only interesting properties to the user. - let isInterestingProp = this.props.isInterestingProp || ((type, value) => { - return type == "boolean" || type == "number" || type == "string" && value.length != 0; - }); + function propIterator(props, object, max) { + if (object.preview && Object.keys(object.preview).includes("wrappedValue")) { + const { Rep } = __webpack_require__(2); - let properties = object.preview ? object.preview.ownProperties : {}; - let propertiesLength = object.preview && object.preview.ownPropertiesLength ? object.preview.ownPropertiesLength : object.ownPropertyLength; + return [Rep({ + object: object.preview.wrappedValue, + mode: props.mode || MODE.TINY, + defaultRep: Grip + })]; + } - if (object.preview && object.preview.safeGetterValues) { - properties = Object.assign({}, properties, object.preview.safeGetterValues); - propertiesLength += Object.keys(object.preview.safeGetterValues).length; - } + // Property filter. Show only interesting properties to the user. + let isInterestingProp = props.isInterestingProp || ((type, value) => { + return type == "boolean" || type == "number" || type == "string" && value.length != 0; + }); - let indexes = this.getPropIndexes(properties, max, isInterestingProp); - if (indexes.length < max && indexes.length < propertiesLength) { - // There are not enough props yet. Then add uninteresting props to display them. - indexes = indexes.concat(this.getPropIndexes(properties, max - indexes.length, (t, value, name) => { - return !isInterestingProp(t, value, name); - })); - } + let properties = object.preview ? object.preview.ownProperties : {}; + let propertiesLength = object.preview && object.preview.ownPropertiesLength ? object.preview.ownPropertiesLength : object.ownPropertyLength; - const truncate = Object.keys(properties).length > max; - // The server synthesizes some property names for a Proxy, like - // and ; we don't want to quote these because, - // as synthetic properties, they appear more natural when - // unquoted. - const suppressQuotes = object.class === "Proxy"; - let propsArray = this.getProps(properties, indexes, truncate, suppressQuotes); - if (truncate) { - // There are some undisplayed props. Then display "more...". - propsArray.push(Caption({ - object: this.safeObjectLink({}, `${propertiesLength - max} more…`) - })); - } + if (object.preview && object.preview.safeGetterValues) { + properties = Object.assign({}, properties, object.preview.safeGetterValues); + propertiesLength += Object.keys(object.preview.safeGetterValues).length; + } - return propsArray; - }, + let indexes = getPropIndexes(properties, max, isInterestingProp); + if (indexes.length < max && indexes.length < propertiesLength) { + // There are not enough props yet. Then add uninteresting props to display them. + indexes = indexes.concat(getPropIndexes(properties, max - indexes.length, (t, value, name) => { + return !isInterestingProp(t, value, name); + })); + } - /** - * Get props ordered by index. - * - * @param {Object} properties Props object. - * @param {Array} indexes Indexes of props. - * @param {Boolean} truncate true if the grip will be truncated. - * @param {Boolean} suppressQuotes true if we should suppress quotes - * on property names. - * @return {Array} Props. - */ - getProps: function (properties, indexes, truncate, suppressQuotes) { - let propsArray = []; + const truncate = Object.keys(properties).length > max; + // The server synthesizes some property names for a Proxy, like + // and ; we don't want to quote these because, + // as synthetic properties, they appear more natural when + // unquoted. + const suppressQuotes = object.class === "Proxy"; + let propsArray = getProps(props, properties, indexes, truncate, suppressQuotes); + if (truncate) { + // There are some undisplayed props. Then display "more...". + propsArray.push(Caption({ + object: safeObjectLink(props, {}, `${propertiesLength - max} more…`) + })); + } - // Make indexes ordered by ascending. - indexes.sort(function (a, b) { - return a - b; - }); + return propsArray; + } - indexes.forEach(i => { - let name = Object.keys(properties)[i]; - let value = this.getPropValue(properties[name]); + /** + * Get props ordered by index. + * + * @param {Object} componentProps Grip Component props. + * @param {Object} properties Properties of the object the Grip describes. + * @param {Array} indexes Indexes of properties. + * @param {Boolean} truncate true if the grip will be truncated. + * @param {Boolean} suppressQuotes true if we should suppress quotes + * on property names. + * @return {Array} Props. + */ + function getProps(componentProps, properties, indexes, truncate, suppressQuotes) { + // Make indexes ordered by ascending. + indexes.sort(function (a, b) { + return a - b; + }); - let propRepProps = Object.assign({}, this.props, { - mode: MODE.TINY, - name: name, - object: value, - equal: ": ", - delim: i !== indexes.length - 1 || truncate ? ", " : "", - defaultRep: Grip, - // Do not propagate title to properties reps - title: undefined, - suppressQuotes - }); - delete propRepProps.objectLink; - propsArray.push(PropRep(propRepProps)); - }); + const propertiesKeys = Object.keys(properties); + return indexes.map(i => { + let name = propertiesKeys[i]; + let value = getPropValue(properties[name]); - return propsArray; - }, + return PropRep(Object.assign({}, componentProps, { + mode: MODE.TINY, + name, + object: value, + equal: ": ", + delim: i !== indexes.length - 1 || truncate ? ", " : null, + defaultRep: Grip, + // Do not propagate title and objectLink to properties reps + title: null, + objectLink: null, + suppressQuotes + })); + }); + } - /** - * Get the indexes of props in the object. - * - * @param {Object} properties Props object. - * @param {Number} max The maximum length of indexes array. - * @param {Function} filter Filter the props you want. - * @return {Array} Indexes of interesting props in the object. - */ - getPropIndexes: function (properties, max, filter) { - let indexes = []; + /** + * Get the indexes of props in the object. + * + * @param {Object} properties Props object. + * @param {Number} max The maximum length of indexes array. + * @param {Function} filter Filter the props you want. + * @return {Array} Indexes of interesting props in the object. + */ + function getPropIndexes(properties, max, filter) { + let indexes = []; - try { - let i = 0; - for (let name in properties) { - if (indexes.length >= max) { - return indexes; - } - - // Type is specified in grip's "class" field and for primitive - // values use typeof. - let value = this.getPropValue(properties[name]); - let type = value.class || typeof value; - type = type.toLowerCase(); - - if (filter(type, value, name)) { - indexes.push(i); - } - i++; + try { + let i = 0; + for (let name in properties) { + if (indexes.length >= max) { + return indexes; } - } catch (err) { - console.error(err); - } - return indexes; - }, - /** - * Get the actual value of a property. - * - * @param {Object} property - * @return {Object} Value of the property. - */ - getPropValue: function (property) { - let value = property; - if (typeof property === "object") { - let keys = Object.keys(property); - if (keys.includes("value")) { - value = property.value; - } else if (keys.includes("getterValue")) { - value = property.getterValue; + // Type is specified in grip's "class" field and for primitive + // values use typeof. + let value = getPropValue(properties[name]); + let type = value.class || typeof value; + type = type.toLowerCase(); + + if (filter(type, value, name)) { + indexes.push(i); } + i++; } - return value; - }, + } catch (err) { + console.error(err); + } + return indexes; + } - safeObjectLink: function (config, ...children) { - if (this.props.objectLink) { - return this.props.objectLink(Object.assign({ - object: this.props.object - }, config), ...children); + /** + * Get the actual value of a property. + * + * @param {Object} property + * @return {Object} Value of the property. + */ + function getPropValue(property) { + let value = property; + if (typeof property === "object") { + let keys = Object.keys(property); + if (keys.includes("value")) { + value = property.value; + } else if (keys.includes("getterValue")) { + value = property.getterValue; } - - if (Object.keys(config).length === 0 && children.length === 1) { - return children[0]; - } - - return span(config, ...children); - }, - - render: wrapRender(function () { - let object = this.props.object; - let propsArray = this.safePropIterator(object, this.props.mode === MODE.LONG ? 10 : 3); - - if (this.props.mode === MODE.TINY) { - return span({ className: "objectBox objectBox-object" }, this.getTitle(object)); - } - - return span({ className: "objectBox objectBox-object" }, this.getTitle(object), this.safeObjectLink({ - className: "objectLeftBrace" - }, " { "), ...propsArray, this.safeObjectLink({ - className: "objectRightBrace" - }, " }")); - }) - }); + } + return value; + } // Registration function supportsObject(object, type) { @@ -1621,8 +1530,8 @@ return /******/ (function(modules) { // webpackBootstrap // Grip is used in propIterator and has to be defined here. let Grip = { - rep: GripRep, - supportsObject: supportsObject + rep: wrapRender(GripRep), + supportsObject }; // Exports from this module @@ -1633,9 +1542,9 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // Dependencies - const React = __webpack_require__(3); + const React = __webpack_require__(4); - const { wrapRender } = __webpack_require__(4); + const { wrapRender } = __webpack_require__(3); // Shortcuts const { span } = React.DOM; @@ -1643,20 +1552,16 @@ return /******/ (function(modules) { // webpackBootstrap /** * Renders a symbol. */ - const SymbolRep = React.createClass({ - displayName: "SymbolRep", + SymbolRep.propTypes = { + object: React.PropTypes.object.isRequired + }; - propTypes: { - object: React.PropTypes.object.isRequired - }, + function SymbolRep(props) { + let { object } = props; + let { name } = object; - render: wrapRender(function () { - let { object } = this.props; - let { name } = object; - - return span({ className: "objectBox objectBox-symbol" }, `Symbol(${name || ""})`); - }) - }); + return span({ className: "objectBox objectBox-symbol" }, `Symbol(${name || ""})`); + } function supportsObject(object, type) { return type == "symbol"; @@ -1664,8 +1569,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: SymbolRep, - supportsObject: supportsObject + rep: wrapRender(SymbolRep), + supportsObject }; /***/ }, @@ -1673,9 +1578,9 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // Dependencies - const React = __webpack_require__(3); + const React = __webpack_require__(4); - const { wrapRender } = __webpack_require__(4); + const { wrapRender } = __webpack_require__(3); // Shortcuts const { span } = React.DOM; @@ -1683,17 +1588,13 @@ return /******/ (function(modules) { // webpackBootstrap /** * Renders a Infinity object */ - const InfinityRep = React.createClass({ - displayName: "Infinity", + InfinityRep.propTypes = { + object: React.PropTypes.object.isRequired + }; - propTypes: { - object: React.PropTypes.object.isRequired - }, - - render: wrapRender(function () { - return span({ className: "objectBox objectBox-number" }, this.props.object.type); - }) - }); + function InfinityRep(props) { + return span({ className: "objectBox objectBox-number" }, props.object.type); + } function supportsObject(object, type) { return type == "Infinity" || type == "-Infinity"; @@ -1701,8 +1602,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: InfinityRep, - supportsObject: supportsObject + rep: wrapRender(InfinityRep), + supportsObject }; /***/ }, @@ -1710,9 +1611,9 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // Dependencies - const React = __webpack_require__(3); + const React = __webpack_require__(4); - const { wrapRender } = __webpack_require__(4); + const { wrapRender } = __webpack_require__(3); // Shortcuts const { span } = React.DOM; @@ -1720,13 +1621,9 @@ return /******/ (function(modules) { // webpackBootstrap /** * Renders a NaN object */ - const NaNRep = React.createClass({ - displayName: "NaN", - - render: wrapRender(function () { - return span({ className: "objectBox objectBox-nan" }, "NaN"); - }) - }); + function NaNRep(props) { + return span({ className: "objectBox objectBox-nan" }, "NaN"); + } function supportsObject(object, type) { return type == "NaN"; @@ -1734,8 +1631,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: NaNRep, - supportsObject: supportsObject + rep: wrapRender(NaNRep), + supportsObject }; /***/ }, @@ -1743,51 +1640,41 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // ReactJS - const React = __webpack_require__(3); + const React = __webpack_require__(4); // Reps const { - createFactories, isGrip, + safeObjectLink, wrapRender - } = __webpack_require__(4); - const StringRep = __webpack_require__(8); + } = __webpack_require__(3); + const { rep: StringRep } = __webpack_require__(8); // Shortcuts const { span } = React.DOM; - const { rep: StringRepFactory } = createFactories(StringRep); /** * Renders DOM attribute */ - let Attribute = React.createClass({ - displayName: "Attr", + Attribute.propTypes = { + object: React.PropTypes.object.isRequired, + objectLink: React.PropTypes.func + }; - propTypes: { - object: React.PropTypes.object.isRequired, - objectLink: React.PropTypes.func - }, + function Attribute(props) { + let { + object + } = props; + let value = object.preview.value; - getTitle: function (grip) { - return grip.preview.nodeName; - }, + return safeObjectLink(props, { className: "objectLink-Attr" }, span({ className: "attrTitle" }, getTitle(object)), span({ className: "attrEqual" }, "="), StringRep({ object: value })); + } - render: wrapRender(function () { - let object = this.props.object; - let value = object.preview.value; - let objectLink = (config, ...children) => { - if (this.props.objectLink) { - return this.props.objectLink(Object.assign({ object }, config), ...children); - } - return span(config, ...children); - }; - - return objectLink({ className: "objectLink-Attr" }, span({ className: "attrTitle" }, this.getTitle(object)), span({ className: "attrEqual" }, "="), StringRepFactory({ object: value })); - }) - }); + function getTitle(grip) { + return grip.preview.nodeName; + } // Registration - function supportsObject(grip, type) { if (!isGrip(grip)) { return false; @@ -1797,8 +1684,8 @@ return /******/ (function(modules) { // webpackBootstrap } module.exports = { - rep: Attribute, - supportsObject: supportsObject + rep: wrapRender(Attribute), + supportsObject }; /***/ }, @@ -1806,13 +1693,14 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // ReactJS - const React = __webpack_require__(3); + const React = __webpack_require__(4); // Reps const { isGrip, + safeObjectLink, wrapRender - } = __webpack_require__(4); + } = __webpack_require__(3); // Shortcuts const { span } = React.DOM; @@ -1820,38 +1708,28 @@ return /******/ (function(modules) { // webpackBootstrap /** * Used to render JS built-in Date() object. */ - let DateTime = React.createClass({ - displayName: "Date", + DateTime.propTypes = { + object: React.PropTypes.object.isRequired, + objectLink: React.PropTypes.func + }; - propTypes: { - object: React.PropTypes.object.isRequired, - objectLink: React.PropTypes.func - }, + function DateTime(props) { + let grip = props.object; + let date; + try { + date = span({ className: "objectBox" }, getTitle(props, grip), span({ className: "Date" }, new Date(grip.preview.timestamp).toISOString())); + } catch (e) { + date = span({ className: "objectBox" }, "Invalid Date"); + } - getTitle: function (grip) { - if (this.props.objectLink) { - return this.props.objectLink({ - object: grip - }, grip.class + " "); - } - return ""; - }, + return date; + } - render: wrapRender(function () { - let grip = this.props.object; - let date; - try { - date = span({ className: "objectBox" }, this.getTitle(grip), span({ className: "Date" }, new Date(grip.preview.timestamp).toISOString())); - } catch (e) { - date = span({ className: "objectBox" }, "Invalid Date"); - } - - return date; - }) - }); + function getTitle(props, grip) { + return safeObjectLink(props, {}, grip.class + " "); + } // Registration - function supportsObject(grip, type) { if (!isGrip(grip)) { return false; @@ -1862,8 +1740,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: DateTime, - supportsObject: supportsObject + rep: wrapRender(DateTime), + supportsObject }; /***/ }, @@ -1871,14 +1749,15 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // ReactJS - const React = __webpack_require__(3); + const React = __webpack_require__(4); // Reps const { isGrip, getURLDisplayString, + safeObjectLink, wrapRender - } = __webpack_require__(4); + } = __webpack_require__(3); // Shortcuts const { span } = React.DOM; @@ -1886,41 +1765,27 @@ return /******/ (function(modules) { // webpackBootstrap /** * Renders DOM document object. */ - let Document = React.createClass({ - displayName: "Document", + Document.propTypes = { + object: React.PropTypes.object.isRequired, + objectLink: React.PropTypes.func + }; - propTypes: { - object: React.PropTypes.object.isRequired, - objectLink: React.PropTypes.func - }, + function Document(props) { + let grip = props.object; - getLocation: function (grip) { - let location = grip.preview.location; - return location ? getURLDisplayString(location) : ""; - }, + return span({ className: "objectBox objectBox-object" }, getTitle(props, grip), span({ className: "objectPropValue" }, getLocation(grip))); + } - getTitle: function (grip) { - if (this.props.objectLink) { - return span({ className: "objectBox" }, this.props.objectLink({ - object: grip - }, grip.class + " ")); - } - return ""; - }, + function getLocation(grip) { + let location = grip.preview.location; + return location ? getURLDisplayString(location) : ""; + } - getTooltip: function (doc) { - return doc.location.href; - }, - - render: wrapRender(function () { - let grip = this.props.object; - - return span({ className: "objectBox objectBox-object" }, this.getTitle(grip), span({ className: "objectPropValue" }, this.getLocation(grip))); - }) - }); + function getTitle(props, grip) { + return safeObjectLink(props, {}, grip.class + " "); + } // Registration - function supportsObject(object, type) { if (!isGrip(object)) { return false; @@ -1931,8 +1796,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: Document, - supportsObject: supportsObject + rep: wrapRender(Document), + supportsObject }; /***/ }, @@ -1940,95 +1805,88 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // ReactJS - const React = __webpack_require__(3); + const React = __webpack_require__(4); // Reps const { - createFactories, isGrip, wrapRender - } = __webpack_require__(4); + } = __webpack_require__(3); - const { rep } = createFactories(__webpack_require__(15)); const { MODE } = __webpack_require__(1); + const { rep } = __webpack_require__(15); /** * Renders DOM event objects. */ - let Event = React.createClass({ - displayName: "event", + Event.propTypes = { + object: React.PropTypes.object.isRequired, + objectLink: React.PropTypes.func, + // @TODO Change this to Object.values once it's supported in Node's version of V8 + mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + onDOMNodeMouseOver: React.PropTypes.func, + onDOMNodeMouseOut: React.PropTypes.func, + onInspectIconClick: React.PropTypes.func + }; - propTypes: { - object: React.PropTypes.object.isRequired, - objectLink: React.PropTypes.func, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - attachedActorIds: React.PropTypes.array, - onDOMNodeMouseOver: React.PropTypes.func, - onDOMNodeMouseOut: React.PropTypes.func, - onInspectIconClick: React.PropTypes.func - }, + function Event(props) { + // Use `Object.assign` to keep `props` without changes because: + // 1. JSON.stringify/JSON.parse is slow. + // 2. Immutable.js is planned for the future. + let gripProps = Object.assign({}, props, { + title: getTitle(props) + }); + gripProps.object = Object.assign({}, props.object); + gripProps.object.preview = Object.assign({}, props.object.preview); - getTitle: function (props) { - let preview = props.object.preview; - let title = preview.type; - - if (preview.eventKind == "key" && preview.modifiers && preview.modifiers.length) { - title = `${title} ${preview.modifiers.join("-")}`; - } - return title; - }, - - render: wrapRender(function () { - // Use `Object.assign` to keep `this.props` without changes because: - // 1. JSON.stringify/JSON.parse is slow. - // 2. Immutable.js is planned for the future. - let gripProps = Object.assign({}, this.props, { - title: this.getTitle(this.props) + gripProps.object.preview.ownProperties = {}; + if (gripProps.object.preview.target) { + Object.assign(gripProps.object.preview.ownProperties, { + target: gripProps.object.preview.target }); - gripProps.object = Object.assign({}, this.props.object); - gripProps.object.preview = Object.assign({}, this.props.object.preview); + } + Object.assign(gripProps.object.preview.ownProperties, gripProps.object.preview.properties); - gripProps.object.preview.ownProperties = {}; - if (gripProps.object.preview.target) { - Object.assign(gripProps.object.preview.ownProperties, { - target: gripProps.object.preview.target - }); - } - Object.assign(gripProps.object.preview.ownProperties, gripProps.object.preview.properties); + delete gripProps.object.preview.properties; + gripProps.object.ownPropertyLength = Object.keys(gripProps.object.preview.ownProperties).length; - delete gripProps.object.preview.properties; - gripProps.object.ownPropertyLength = Object.keys(gripProps.object.preview.ownProperties).length; + switch (gripProps.object.class) { + case "MouseEvent": + gripProps.isInterestingProp = (type, value, name) => { + return ["target", "clientX", "clientY", "layerX", "layerY"].includes(name); + }; + break; + case "KeyboardEvent": + gripProps.isInterestingProp = (type, value, name) => { + return ["target", "key", "charCode", "keyCode"].includes(name); + }; + break; + case "MessageEvent": + gripProps.isInterestingProp = (type, value, name) => { + return ["target", "isTrusted", "data"].includes(name); + }; + break; + default: + gripProps.isInterestingProp = (type, value, name) => { + // We want to show the properties in the order they are declared. + return Object.keys(gripProps.object.preview.ownProperties).includes(name); + }; + } - switch (gripProps.object.class) { - case "MouseEvent": - gripProps.isInterestingProp = (type, value, name) => { - return ["target", "clientX", "clientY", "layerX", "layerY"].includes(name); - }; - break; - case "KeyboardEvent": - gripProps.isInterestingProp = (type, value, name) => { - return ["target", "key", "charCode", "keyCode"].includes(name); - }; - break; - case "MessageEvent": - gripProps.isInterestingProp = (type, value, name) => { - return ["target", "isTrusted", "data"].includes(name); - }; - break; - default: - gripProps.isInterestingProp = (type, value, name) => { - // We want to show the properties in the order they are declared. - return Object.keys(gripProps.object.preview.ownProperties).includes(name); - }; - } + return rep(gripProps); + } - return rep(gripProps); - }) - }); + function getTitle(props) { + let preview = props.object.preview; + let title = preview.type; + + if (preview.eventKind == "key" && preview.modifiers && preview.modifiers.length) { + title = `${title} ${preview.modifiers.join("-")}`; + } + return title; + } // Registration - function supportsObject(grip, type) { if (!isGrip(grip)) { return false; @@ -2039,8 +1897,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: Event, - supportsObject: supportsObject + rep: wrapRender(Event), + supportsObject }; /***/ }, @@ -2048,14 +1906,15 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // ReactJS - const React = __webpack_require__(3); + const React = __webpack_require__(4); // Reps const { isGrip, cropString, + safeObjectLink, wrapRender - } = __webpack_require__(4); + } = __webpack_require__(3); // Shortcuts const { span } = React.DOM; @@ -2063,50 +1922,39 @@ return /******/ (function(modules) { // webpackBootstrap /** * This component represents a template for Function objects. */ - let Func = React.createClass({ - displayName: "Func", + FunctionRep.propTypes = { + object: React.PropTypes.object.isRequired, + objectLink: React.PropTypes.func + }; - propTypes: { - object: React.PropTypes.object.isRequired, - objectLink: React.PropTypes.func - }, + function FunctionRep(props) { + let grip = props.object; - getTitle: function (grip) { - let title = "function "; - if (grip.isGenerator) { - title = "function* "; - } - if (grip.isAsync) { - title = "async " + title; - } + return ( + // Set dir="ltr" to prevent function parentheses from + // appearing in the wrong direction + span({ dir: "ltr", className: "objectBox objectBox-function" }, getTitle(props, grip), summarizeFunction(grip)) + ); + } - if (this.props.objectLink) { - return this.props.objectLink({ - object: grip - }, title); - } + function getTitle(props, grip) { + let title = "function "; + if (grip.isGenerator) { + title = "function* "; + } + if (grip.isAsync) { + title = "async " + title; + } - return title; - }, + return safeObjectLink(props, {}, title); + } - summarizeFunction: function (grip) { - let name = grip.userDisplayName || grip.displayName || grip.name || ""; - return cropString(name + "()", 100); - }, - - render: wrapRender(function () { - let grip = this.props.object; - - return ( - // Set dir="ltr" to prevent function parentheses from - // appearing in the wrong direction - span({ dir: "ltr", className: "objectBox objectBox-function" }, this.getTitle(grip), this.summarizeFunction(grip)) - ); - }) - }); + function summarizeFunction(grip) { + let name = grip.userDisplayName || grip.displayName || grip.name || ""; + return cropString(name + "()", 100); + } // Registration - function supportsObject(grip, type) { if (!isGrip(grip)) { return type == "function"; @@ -2118,8 +1966,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: Func, - supportsObject: supportsObject + rep: wrapRender(FunctionRep), + supportsObject }; /***/ }, @@ -2127,15 +1975,15 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // ReactJS - const React = __webpack_require__(3); + const React = __webpack_require__(4); // Dependencies const { - createFactories, isGrip, + safeObjectLink, wrapRender - } = __webpack_require__(4); + } = __webpack_require__(3); - const PropRep = React.createFactory(__webpack_require__(14)); + const PropRep = __webpack_require__(14); const { MODE } = __webpack_require__(1); // Shortcuts const { span } = React.DOM; @@ -2143,80 +1991,61 @@ return /******/ (function(modules) { // webpackBootstrap /** * Renders a DOM Promise object. */ - const PromiseRep = React.createClass({ - displayName: "Promise", + PromiseRep.propTypes = { + object: React.PropTypes.object.isRequired, + // @TODO Change this to Object.values once it's supported in Node's version of V8 + mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + objectLink: React.PropTypes.func, + onDOMNodeMouseOver: React.PropTypes.func, + onDOMNodeMouseOut: React.PropTypes.func, + onInspectIconClick: React.PropTypes.func + }; - propTypes: { - object: React.PropTypes.object.isRequired, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - objectLink: React.PropTypes.func, - attachedActorIds: React.PropTypes.array, - onDOMNodeMouseOver: React.PropTypes.func, - onDOMNodeMouseOut: React.PropTypes.func, - onInspectIconClick: React.PropTypes.func - }, + function PromiseRep(props) { + const object = props.object; + const { promiseState } = object; - getTitle: function (object) { - const title = object.class; - return this.safeObjectLink({}, title); - }, + if (props.mode === MODE.TINY) { + let { Rep } = __webpack_require__(2); - getProps: function (promiseState) { - const keys = ["state"]; - if (Object.keys(promiseState).includes("value")) { - keys.push("value"); - } - - return keys.map((key, i) => { - let object = promiseState[key]; - return PropRep(Object.assign({}, this.props, { - mode: MODE.TINY, - name: `<${key}>`, - object, - equal: ": ", - delim: i < keys.length - 1 ? ", " : "", - suppressQuotes: true - })); - }); - }, - - safeObjectLink: function (config, ...children) { - if (this.props.objectLink) { - return this.props.objectLink(Object.assign({ - object: this.props.object - }, config), ...children); - } - - if (Object.keys(config).length === 0 && children.length === 1) { - return children[0]; - } - - return span(config, ...children); - }, - - render: wrapRender(function () { - const object = this.props.object; - const { promiseState } = object; - - if (this.props.mode === MODE.TINY) { - let { Rep } = createFactories(__webpack_require__(2)); - - return span({ className: "objectBox objectBox-object" }, this.getTitle(object), this.safeObjectLink({ - className: "objectLeftBrace" - }, " { "), Rep({ object: promiseState.state }), this.safeObjectLink({ - className: "objectRightBrace" - }, " }")); - } - - const propsArray = this.getProps(promiseState); - return span({ className: "objectBox objectBox-object" }, this.getTitle(object), this.safeObjectLink({ + return span({ className: "objectBox objectBox-object" }, getTitle(props, object), safeObjectLink(props, { className: "objectLeftBrace" - }, " { "), ...propsArray, this.safeObjectLink({ + }, " { "), Rep({ object: promiseState.state }), safeObjectLink(props, { className: "objectRightBrace" }, " }")); - }) - }); + } + + const propsArray = getProps(props, promiseState); + return span({ className: "objectBox objectBox-object" }, getTitle(props, object), safeObjectLink(props, { + className: "objectLeftBrace" + }, " { "), ...propsArray, safeObjectLink(props, { + className: "objectRightBrace" + }, " }")); + } + + function getTitle(props, object) { + const title = object.class; + return safeObjectLink(props, {}, title); + } + + function getProps(props, promiseState) { + const keys = ["state"]; + if (Object.keys(promiseState).includes("value")) { + keys.push("value"); + } + + return keys.map((key, i) => { + let object = promiseState[key]; + return PropRep(Object.assign({}, props, { + mode: MODE.TINY, + name: `<${key}>`, + object, + equal: ": ", + delim: i < keys.length - 1 ? ", " : null, + suppressQuotes: true + })); + }); + } // Registration function supportsObject(object, type) { @@ -2228,8 +2057,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: PromiseRep, - supportsObject: supportsObject + rep: wrapRender(PromiseRep), + supportsObject }; /***/ }, @@ -2237,49 +2066,36 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // ReactJS - const React = __webpack_require__(3); + const React = __webpack_require__(4); // Reps const { isGrip, + safeObjectLink, wrapRender - } = __webpack_require__(4); - - // Shortcuts - const { span } = React.DOM; + } = __webpack_require__(3); /** * Renders a grip object with regular expression. */ - let RegExp = React.createClass({ - displayName: "regexp", + RegExp.propTypes = { + object: React.PropTypes.object.isRequired, + objectLink: React.PropTypes.func + }; - propTypes: { - object: React.PropTypes.object.isRequired, - objectLink: React.PropTypes.func - }, + function RegExp(props) { + let { object } = props; - getSource: function (grip) { - return grip.displayString; - }, + return safeObjectLink(props, { + className: "objectBox objectBox-regexp regexpSource" + }, getSource(object)); + } - render: wrapRender(function () { - let { object } = this.props; - let objectLink = (config, ...children) => { - if (this.props.objectLink) { - return this.props.objectLink(Object.assign({ object }, config), ...children); - } - return span(config, ...children); - }; - - return objectLink({ - className: "objectBox objectBox-regexp regexpSource" - }, this.getSource(object)); - }) - }); + function getSource(grip) { + return grip.displayString; + } // Registration - function supportsObject(object, type) { if (!isGrip(object)) { return false; @@ -2290,8 +2106,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: RegExp, - supportsObject: supportsObject + rep: wrapRender(RegExp), + supportsObject }; /***/ }, @@ -2299,54 +2115,45 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // ReactJS - const React = __webpack_require__(3); + const React = __webpack_require__(4); // Reps const { isGrip, getURLDisplayString, + safeObjectLink, wrapRender - } = __webpack_require__(4); + } = __webpack_require__(3); // Shortcuts - const DOM = React.DOM; + const { span } = React.DOM; /** * Renders a grip representing CSSStyleSheet */ - let StyleSheet = React.createClass({ - displayName: "object", + StyleSheet.propTypes = { + object: React.PropTypes.object.isRequired, + objectLink: React.PropTypes.func + }; - propTypes: { - object: React.PropTypes.object.isRequired, - objectLink: React.PropTypes.func - }, + function StyleSheet(props) { + let grip = props.object; - getTitle: function (grip) { - let title = "StyleSheet "; - if (this.props.objectLink) { - return DOM.span({ className: "objectBox" }, this.props.objectLink({ - object: grip - }, title)); - } - return title; - }, + return span({ className: "objectBox objectBox-object" }, getTitle(props, grip), span({ className: "objectPropValue" }, getLocation(grip))); + } - getLocation: function (grip) { - // Embedded stylesheets don't have URL and so, no preview. - let url = grip.preview ? grip.preview.url : ""; - return url ? getURLDisplayString(url) : ""; - }, + function getTitle(props, grip) { + let title = "StyleSheet "; + return safeObjectLink(props, { className: "objectBox" }, title); + } - render: wrapRender(function () { - let grip = this.props.object; - - return DOM.span({ className: "objectBox objectBox-object" }, this.getTitle(grip), DOM.span({ className: "objectPropValue" }, this.getLocation(grip))); - }) - }); + function getLocation(grip) { + // Embedded stylesheets don't have URL and so, no preview. + let url = grip.preview ? grip.preview.url : ""; + return url ? getURLDisplayString(url) : ""; + } // Registration - function supportsObject(object, type) { if (!isGrip(object)) { return false; @@ -2358,8 +2165,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: StyleSheet, - supportsObject: supportsObject + rep: wrapRender(StyleSheet), + supportsObject }; /***/ }, @@ -2367,13 +2174,13 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // Dependencies - const React = __webpack_require__(3); + const React = __webpack_require__(4); const { isGrip, cropString, cropMultipleLines, wrapRender - } = __webpack_require__(4); + } = __webpack_require__(3); const { MODE } = __webpack_require__(1); const nodeConstants = __webpack_require__(5); @@ -2383,31 +2190,27 @@ return /******/ (function(modules) { // webpackBootstrap /** * Renders DOM comment node. */ - const CommentNode = React.createClass({ - displayName: "CommentNode", + CommentNode.propTypes = { + object: React.PropTypes.object.isRequired, + // @TODO Change this to Object.values once it's supported in Node's version of V8 + mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])) + }; - propTypes: { - object: React.PropTypes.object.isRequired, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])) - }, + function CommentNode(props) { + let { + object, + mode = MODE.SHORT + } = props; - render: wrapRender(function () { - let { - object, - mode = MODE.SHORT - } = this.props; + let { textContent } = object.preview; + if (mode === MODE.TINY) { + textContent = cropMultipleLines(textContent, 30); + } else if (mode === MODE.SHORT) { + textContent = cropString(textContent, 50); + } - let { textContent } = object.preview; - if (mode === MODE.TINY) { - textContent = cropMultipleLines(textContent, 30); - } else if (mode === MODE.SHORT) { - textContent = cropString(textContent, 50); - } - - return span({ className: "objectBox theme-comment" }, ``); - }) - }); + return span({ className: "objectBox theme-comment" }, ``); + } // Registration function supportsObject(object, type) { @@ -2419,8 +2222,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: CommentNode, - supportsObject: supportsObject + rep: wrapRender(CommentNode), + supportsObject }; /***/ }, @@ -2428,13 +2231,14 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // ReactJS - const React = __webpack_require__(3); + const React = __webpack_require__(4); // Utils const { isGrip, + safeObjectLink, wrapRender - } = __webpack_require__(4); + } = __webpack_require__(3); const { MODE } = __webpack_require__(1); const nodeConstants = __webpack_require__(5); const Svg = __webpack_require__(29); @@ -2445,105 +2249,93 @@ return /******/ (function(modules) { // webpackBootstrap /** * Renders DOM element node. */ - const ElementNode = React.createClass({ - displayName: "ElementNode", + ElementNode.propTypes = { + object: React.PropTypes.object.isRequired, + // @TODO Change this to Object.values once it's supported in Node's version of V8 + mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + onDOMNodeMouseOver: React.PropTypes.func, + onDOMNodeMouseOut: React.PropTypes.func, + onInspectIconClick: React.PropTypes.func, + objectLink: React.PropTypes.func + }; - propTypes: { - object: React.PropTypes.object.isRequired, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - attachedActorIds: React.PropTypes.array, - onDOMNodeMouseOver: React.PropTypes.func, - onDOMNodeMouseOut: React.PropTypes.func, - onInspectIconClick: React.PropTypes.func, - objectLink: React.PropTypes.func - }, + function ElementNode(props) { + let { + object, + mode, + onDOMNodeMouseOver, + onDOMNodeMouseOut, + onInspectIconClick + } = props; + let elements = getElements(object, mode); - getElements: function (grip, mode) { - let { attributes, nodeName } = grip.preview; - const nodeNameElement = span({ - className: "tag-name theme-fg-color3" - }, nodeName); + let isInTree = object.preview && object.preview.isConnected === true; - if (mode === MODE.TINY) { - let elements = [nodeNameElement]; - if (attributes.id) { - elements.push(span({ className: "attr-name theme-fg-color2" }, `#${attributes.id}`)); - } - if (attributes.class) { - elements.push(span({ className: "attr-name theme-fg-color2" }, attributes.class.replace(/(^\s+)|(\s+$)/g, "").split(" ").map(cls => `.${cls}`).join(""))); - } - return elements; - } - let attributeElements = Object.keys(attributes).sort(function getIdAndClassFirst(a1, a2) { - if ([a1, a2].includes("id")) { - return 3 * (a1 === "id" ? -1 : 1); - } - if ([a1, a2].includes("class")) { - return 2 * (a1 === "class" ? -1 : 1); - } - - // `id` and `class` excepted, - // we want to keep the same order that in `attributes`. - return 0; - }).reduce((arr, name, i, keys) => { - let value = attributes[name]; - let attribute = span({}, span({ className: "attr-name theme-fg-color2" }, `${name}`), `="`, span({ className: "attr-value theme-fg-color6" }, `${value}`), `"`); - - return arr.concat([" ", attribute]); - }, []); - - return ["<", nodeNameElement, ...attributeElements, ">"]; - }, - - render: wrapRender(function () { - let { - object, - mode, - attachedActorIds, - onDOMNodeMouseOver, - onDOMNodeMouseOut, - onInspectIconClick - } = this.props; - let elements = this.getElements(object, mode); - let objectLink = (config, ...children) => { - if (this.props.objectLink) { - return this.props.objectLink(Object.assign({ object }, config), ...children); - } - return span(config, ...children); - }; - - let isInTree = attachedActorIds ? attachedActorIds.includes(object.actor) : true; - - let baseConfig = { className: "objectBox objectBox-node" }; - let inspectIcon; - if (isInTree) { - if (onDOMNodeMouseOver) { - Object.assign(baseConfig, { - onMouseOver: _ => onDOMNodeMouseOver(object) - }); - } - - if (onDOMNodeMouseOut) { - Object.assign(baseConfig, { - onMouseOut: onDOMNodeMouseOut - }); - } - - if (onInspectIconClick) { - inspectIcon = Svg("open-inspector", { - element: "a", - draggable: false, - // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands - title: "Click to select the node in the inspector", - onClick: e => onInspectIconClick(object, e) - }); - } + let baseConfig = { className: "objectBox objectBox-node" }; + let inspectIcon; + if (isInTree) { + if (onDOMNodeMouseOver) { + Object.assign(baseConfig, { + onMouseOver: _ => onDOMNodeMouseOver(object) + }); } - return span(baseConfig, objectLink({}, ...elements), inspectIcon); - }) - }); + if (onDOMNodeMouseOut) { + Object.assign(baseConfig, { + onMouseOut: onDOMNodeMouseOut + }); + } + + if (onInspectIconClick) { + inspectIcon = Svg("open-inspector", { + element: "a", + draggable: false, + // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands + title: "Click to select the node in the inspector", + onClick: e => onInspectIconClick(object, e) + }); + } + } + + return span(baseConfig, safeObjectLink(props, {}, ...elements), inspectIcon); + } + + function getElements(grip, mode) { + let { attributes, nodeName } = grip.preview; + const nodeNameElement = span({ + className: "tag-name theme-fg-color3" + }, nodeName); + + if (mode === MODE.TINY) { + let elements = [nodeNameElement]; + if (attributes.id) { + elements.push(span({ className: "attr-name theme-fg-color2" }, `#${attributes.id}`)); + } + if (attributes.class) { + elements.push(span({ className: "attr-name theme-fg-color2" }, attributes.class.replace(/(^\s+)|(\s+$)/g, "").split(" ").map(cls => `.${cls}`).join(""))); + } + return elements; + } + let attributeElements = Object.keys(attributes).sort(function getIdAndClassFirst(a1, a2) { + if ([a1, a2].includes("id")) { + return 3 * (a1 === "id" ? -1 : 1); + } + if ([a1, a2].includes("class")) { + return 2 * (a1 === "class" ? -1 : 1); + } + + // `id` and `class` excepted, + // we want to keep the same order that in `attributes`. + return 0; + }).reduce((arr, name, i, keys) => { + let value = attributes[name]; + let attribute = span({}, span({ className: "attr-name theme-fg-color2" }, `${name}`), `="`, span({ className: "attr-value theme-fg-color6" }, `${value}`), `"`); + + return arr.concat([" ", attribute]); + }, []); + + return ["<", nodeNameElement, ...attributeElements, ">"]; + } // Registration function supportsObject(object, type) { @@ -2555,15 +2347,15 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: ElementNode, - supportsObject: supportsObject + rep: wrapRender(ElementNode), + supportsObject }; /***/ }, /* 29 */ /***/ function(module, exports, __webpack_require__) { - const React = __webpack_require__(3); + const React = __webpack_require__(4); const InlineSVG = __webpack_require__(30); const svg = { @@ -2610,7 +2402,7 @@ return /******/ (function(modules) { // webpackBootstrap function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - var _react = __webpack_require__(3); + var _react = __webpack_require__(4); var _react2 = _interopRequireDefault(_react); @@ -2749,14 +2541,15 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // ReactJS - const React = __webpack_require__(3); + const React = __webpack_require__(4); // Reps const { isGrip, cropString, + safeObjectLink, wrapRender - } = __webpack_require__(4); + } = __webpack_require__(3); const { MODE } = __webpack_require__(1); const Svg = __webpack_require__(29); @@ -2766,82 +2559,70 @@ return /******/ (function(modules) { // webpackBootstrap /** * Renders DOM #text node. */ - let TextNode = React.createClass({ - displayName: "TextNode", + TextNode.propTypes = { + object: React.PropTypes.object.isRequired, + // @TODO Change this to Object.values once it's supported in Node's version of V8 + mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + objectLink: React.PropTypes.func, + onDOMNodeMouseOver: React.PropTypes.func, + onDOMNodeMouseOut: React.PropTypes.func, + onInspectIconClick: React.PropTypes.func + }; - propTypes: { - object: React.PropTypes.object.isRequired, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - objectLink: React.PropTypes.func, - attachedActorIds: React.PropTypes.array, - onDOMNodeMouseOver: React.PropTypes.func, - onDOMNodeMouseOut: React.PropTypes.func, - onInspectIconClick: React.PropTypes.func - }, + function TextNode(props) { + let { + object: grip, + mode = MODE.SHORT, + onDOMNodeMouseOver, + onDOMNodeMouseOut, + onInspectIconClick + } = props; - getTextContent: function (grip) { - return cropString(grip.preview.textContent); - }, + let baseConfig = { className: "objectBox objectBox-textNode" }; + let inspectIcon; + let isInTree = grip.preview && grip.preview.isConnected === true; - getTitle: function (grip) { - const title = "#text"; - if (this.props.objectLink) { - return this.props.objectLink({ - object: grip - }, title); - } - return title; - }, - - render: wrapRender(function () { - let { - object: grip, - mode = MODE.SHORT, - attachedActorIds, - onDOMNodeMouseOver, - onDOMNodeMouseOut, - onInspectIconClick - } = this.props; - - let baseConfig = { className: "objectBox objectBox-textNode" }; - let inspectIcon; - let isInTree = attachedActorIds ? attachedActorIds.includes(grip.actor) : true; - - if (isInTree) { - if (onDOMNodeMouseOver) { - Object.assign(baseConfig, { - onMouseOver: _ => onDOMNodeMouseOver(grip) - }); - } - - if (onDOMNodeMouseOut) { - Object.assign(baseConfig, { - onMouseOut: onDOMNodeMouseOut - }); - } - - if (onInspectIconClick) { - inspectIcon = Svg("open-inspector", { - element: "a", - draggable: false, - // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands - title: "Click to select the node in the inspector", - onClick: e => onInspectIconClick(grip, e) - }); - } + if (isInTree) { + if (onDOMNodeMouseOver) { + Object.assign(baseConfig, { + onMouseOver: _ => onDOMNodeMouseOver(grip) + }); } - if (mode === MODE.TINY) { - return DOM.span(baseConfig, this.getTitle(grip), inspectIcon); + if (onDOMNodeMouseOut) { + Object.assign(baseConfig, { + onMouseOut: onDOMNodeMouseOut + }); } - return DOM.span(baseConfig, this.getTitle(grip), DOM.span({ className: "nodeValue" }, " ", `"${this.getTextContent(grip)}"`), inspectIcon); - }) - }); + if (onInspectIconClick) { + inspectIcon = Svg("open-inspector", { + element: "a", + draggable: false, + // TODO: Localize this with "openNodeInInspector" when Bug 1317038 lands + title: "Click to select the node in the inspector", + onClick: e => onInspectIconClick(grip, e) + }); + } + } + + if (mode === MODE.TINY) { + return DOM.span(baseConfig, getTitle(props, grip), inspectIcon); + } + + return DOM.span(baseConfig, getTitle(props, grip), DOM.span({ className: "nodeValue" }, " ", `"${getTextContent(grip)}"`), inspectIcon); + } + + function getTextContent(grip) { + return cropString(grip.preview.textContent); + } + + function getTitle(props, grip) { + const title = "#text"; + return safeObjectLink(props, {}, title); + } // Registration - function supportsObject(grip, type) { if (!isGrip(grip)) { return false; @@ -2852,8 +2633,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: TextNode, - supportsObject: supportsObject + rep: wrapRender(TextNode), + supportsObject }; /***/ }, @@ -2861,55 +2642,43 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // ReactJS - const React = __webpack_require__(3); + const React = __webpack_require__(4); // Utils const { isGrip, + safeObjectLink, wrapRender - } = __webpack_require__(4); + } = __webpack_require__(3); const { MODE } = __webpack_require__(1); - // Shortcuts - const { span } = React.DOM; /** * Renders Error objects. */ - const ErrorRep = React.createClass({ - displayName: "Error", + ErrorRep.propTypes = { + object: React.PropTypes.object.isRequired, + // @TODO Change this to Object.values once it's supported in Node's version of V8 + mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + objectLink: React.PropTypes.func + }; - propTypes: { - object: React.PropTypes.object.isRequired, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - objectLink: React.PropTypes.func - }, + function ErrorRep(props) { + let object = props.object; + let preview = object.preview; + let name = preview && preview.name ? preview.name : "Error"; - render: wrapRender(function () { - let object = this.props.object; - let preview = object.preview; - let name = preview && preview.name ? preview.name : "Error"; + let content = props.mode === MODE.TINY ? name : `${name}: ${preview.message}`; - let content = this.props.mode === MODE.TINY ? name : `${name}: ${preview.message}`; + if (preview.stack && props.mode !== MODE.TINY) { + /* + * Since Reps are used in the JSON Viewer, we can't localize + * the "Stack trace" label (defined in debugger.properties as + * "variablesViewErrorStacktrace" property), until Bug 1317038 lands. + */ + content = `${content}\nStack trace:\n${preview.stack}`; + } - if (preview.stack && this.props.mode !== MODE.TINY) { - /* - * Since Reps are used in the JSON Viewer, we can't localize - * the "Stack trace" label (defined in debugger.properties as - * "variablesViewErrorStacktrace" property), until Bug 1317038 lands. - */ - content = `${content}\nStack trace:\n${preview.stack}`; - } - - let objectLink = (config, ...children) => { - if (this.props.objectLink) { - return this.props.objectLink(Object.assign({ object }, config), ...children); - } - return span(config, ...children); - }; - - return objectLink({ className: "objectBox-stackTrace" }, content); - }) - }); + return safeObjectLink(props, { className: "objectBox-stackTrace" }, content); + } // Registration function supportsObject(object, type) { @@ -2921,8 +2690,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: ErrorRep, - supportsObject: supportsObject + rep: wrapRender(ErrorRep), + supportsObject }; /***/ }, @@ -2930,63 +2699,54 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // ReactJS - const React = __webpack_require__(3); + const React = __webpack_require__(4); // Reps const { isGrip, getURLDisplayString, + safeObjectLink, wrapRender - } = __webpack_require__(4); + } = __webpack_require__(3); const { MODE } = __webpack_require__(1); // Shortcuts - const DOM = React.DOM; + const { span } = React.DOM; /** * Renders a grip representing a window. */ - let Window = React.createClass({ - displayName: "Window", + WindowRep.propTypes = { + // @TODO Change this to Object.values once it's supported in Node's version of V8 + mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + object: React.PropTypes.object.isRequired, + objectLink: React.PropTypes.func + }; - propTypes: { - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - object: React.PropTypes.object.isRequired, - objectLink: React.PropTypes.func - }, + function WindowRep(props) { + let { + mode, + object + } = props; - getTitle: function (object) { - let title = object.displayClass || object.class || "Window"; - if (this.props.objectLink) { - return DOM.span({ className: "objectBox" }, this.props.objectLink({ - object - }, title)); - } - return title; - }, + if (mode === MODE.TINY) { + return span({ className: "objectBox objectBox-Window" }, getTitle(props, object)); + } - getLocation: function (object) { - return getURLDisplayString(object.preview.url); - }, + return span({ className: "objectBox objectBox-Window" }, getTitle(props, object), " ", span({ className: "objectPropValue" }, getLocation(object))); + } - render: wrapRender(function () { - let { - mode, - object - } = this.props; + function getTitle(props, object) { + let title = object.displayClass || object.class || "Window"; + return safeObjectLink(props, { className: "objectBox" }, title); + } - if (mode === MODE.TINY) { - return DOM.span({ className: "objectBox objectBox-Window" }, this.getTitle(object)); - } - - return DOM.span({ className: "objectBox objectBox-Window" }, this.getTitle(object), " ", DOM.span({ className: "objectPropValue" }, this.getLocation(object))); - }) - }); + function getLocation(object) { + return getURLDisplayString(object.preview.url); + } // Registration - function supportsObject(object, type) { if (!isGrip(object)) { return false; @@ -2997,8 +2757,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: Window, - supportsObject: supportsObject + rep: wrapRender(WindowRep), + supportsObject }; /***/ }, @@ -3006,13 +2766,13 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // ReactJS - const React = __webpack_require__(3); + const React = __webpack_require__(4); // Reps const { isGrip, wrapRender - } = __webpack_require__(4); + } = __webpack_require__(3); // Shortcuts const { span } = React.DOM; @@ -3020,39 +2780,34 @@ return /******/ (function(modules) { // webpackBootstrap /** * Renders a grip object with textual data. */ - let ObjectWithText = React.createClass({ - displayName: "ObjectWithText", + ObjectWithText.propTypes = { + object: React.PropTypes.object.isRequired, + objectLink: React.PropTypes.func + }; - propTypes: { - object: React.PropTypes.object.isRequired, - objectLink: React.PropTypes.func - }, + function ObjectWithText(props) { + let grip = props.object; + return span({ className: "objectBox objectBox-" + getType(grip) }, getTitle(props, grip), span({ className: "objectPropValue" }, getDescription(grip))); + } - getTitle: function (grip) { - if (this.props.objectLink) { - return span({ className: "objectBox" }, this.props.objectLink({ - object: grip - }, this.getType(grip) + " ")); - } - return ""; - }, + function getTitle(props, grip) { + if (props.objectLink) { + return span({ className: "objectBox" }, props.objectLink({ + object: grip + }, getType(grip) + " ")); + } + return ""; + } - getType: function (grip) { - return grip.class; - }, + function getType(grip) { + return grip.class; + } - getDescription: function (grip) { - return "\"" + grip.preview.text + "\""; - }, - - render: wrapRender(function () { - let grip = this.props.object; - return span({ className: "objectBox objectBox-" + this.getType(grip) }, this.getTitle(grip), span({ className: "objectPropValue" }, this.getDescription(grip))); - }) - }); + function getDescription(grip) { + return "\"" + grip.preview.text + "\""; + } // Registration - function supportsObject(grip, type) { if (!isGrip(grip)) { return false; @@ -3063,8 +2818,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: ObjectWithText, - supportsObject: supportsObject + rep: wrapRender(ObjectWithText), + supportsObject }; /***/ }, @@ -3072,14 +2827,15 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // ReactJS - const React = __webpack_require__(3); + const React = __webpack_require__(4); // Reps const { isGrip, getURLDisplayString, + safeObjectLink, wrapRender - } = __webpack_require__(4); + } = __webpack_require__(3); // Shortcuts const { span } = React.DOM; @@ -3087,39 +2843,29 @@ return /******/ (function(modules) { // webpackBootstrap /** * Renders a grip object with URL data. */ - let ObjectWithURL = React.createClass({ - displayName: "ObjectWithURL", + ObjectWithURL.propTypes = { + object: React.PropTypes.object.isRequired, + objectLink: React.PropTypes.func + }; - propTypes: { - object: React.PropTypes.object.isRequired, - objectLink: React.PropTypes.func - }, + function ObjectWithURL(props) { + let grip = props.object; + return span({ className: "objectBox objectBox-" + getType(grip) }, getTitle(props, grip), span({ className: "objectPropValue" }, getDescription(grip))); + } - getTitle: function (grip) { - if (this.props.objectLink) { - return span({ className: "objectBox" }, this.props.objectLink({ - object: grip - }, this.getType(grip) + " ")); - } - return ""; - }, + function getTitle(props, grip) { + return safeObjectLink(props, { className: "objectBox" }, getType(grip) + " "); + } - getType: function (grip) { - return grip.class; - }, + function getType(grip) { + return grip.class; + } - getDescription: function (grip) { - return getURLDisplayString(grip.preview.url); - }, - - render: wrapRender(function () { - let grip = this.props.object; - return span({ className: "objectBox objectBox-" + this.getType(grip) }, this.getTitle(grip), span({ className: "objectPropValue" }, this.getDescription(grip))); - }) - }); + function getDescription(grip) { + return getURLDisplayString(grip.preview.url); + } // Registration - function supportsObject(grip, type) { if (!isGrip(grip)) { return false; @@ -3130,8 +2876,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: ObjectWithURL, - supportsObject: supportsObject + rep: wrapRender(ObjectWithURL), + supportsObject }; /***/ }, @@ -3139,13 +2885,13 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // Dependencies - const React = __webpack_require__(3); + const React = __webpack_require__(4); const { - createFactories, isGrip, + safeObjectLink, wrapRender - } = __webpack_require__(4); - const Caption = React.createFactory(__webpack_require__(12)); + } = __webpack_require__(3); + const Caption = __webpack_require__(12); const { MODE } = __webpack_require__(1); // Shortcuts @@ -3155,175 +2901,154 @@ return /******/ (function(modules) { // webpackBootstrap * Renders an array. The array is enclosed by left and right bracket * and the max number of rendered items depends on the current mode. */ - let GripArray = React.createClass({ - displayName: "GripArray", + GripArray.propTypes = { + object: React.PropTypes.object.isRequired, + // @TODO Change this to Object.values once it's supported in Node's version of V8 + mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + provider: React.PropTypes.object, + objectLink: React.PropTypes.func, + onDOMNodeMouseOver: React.PropTypes.func, + onDOMNodeMouseOut: React.PropTypes.func, + onInspectIconClick: React.PropTypes.func + }; - propTypes: { - object: React.PropTypes.object.isRequired, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - provider: React.PropTypes.object, - objectLink: React.PropTypes.func, - attachedActorIds: React.PropTypes.array, - onDOMNodeMouseOver: React.PropTypes.func, - onDOMNodeMouseOut: React.PropTypes.func, - onInspectIconClick: React.PropTypes.func - }, + function GripArray(props) { + let { + object, + mode = MODE.SHORT + } = props; - getLength: function (grip) { - if (!grip.preview) { - return 0; - } + let items; + let brackets; + let needSpace = function (space) { + return space ? { left: "[ ", right: " ]" } : { left: "[", right: "]" }; + }; - return grip.preview.length || grip.preview.childNodesLength || 0; - }, + if (mode === MODE.TINY) { + let objectLength = getLength(object); + let isEmpty = objectLength === 0; + items = [span({ className: "length" }, isEmpty ? "" : objectLength)]; + brackets = needSpace(false); + } else { + let max = mode === MODE.SHORT ? 3 : 10; + items = arrayIterator(props, object, max); + brackets = needSpace(items.length > 0); + } - getTitle: function (object, context) { - if (this.props.mode === MODE.TINY) { - return ""; - } + let title = getTitle(props, object); - let title = this.props.title || object.class || "Array"; - return this.safeObjectLink({}, title + " "); - }, - - getPreviewItems: function (grip) { - if (!grip.preview) { - return null; - } - - return grip.preview.items || grip.preview.childNodes || null; - }, - - arrayIterator: function (grip, max) { - let items = []; - const gripLength = this.getLength(grip); - - if (!gripLength) { - return items; - } - - const previewItems = this.getPreviewItems(grip); - if (!previewItems) { - return items; - } - - let delim; - // number of grip preview items is limited to 10, but we may have more - // items in grip-array. - let delimMax = gripLength > previewItems.length ? previewItems.length : previewItems.length - 1; - let provider = this.props.provider; - - for (let i = 0; i < previewItems.length && i < max; i++) { - try { - let itemGrip = previewItems[i]; - let value = provider ? provider.getValue(itemGrip) : itemGrip; - - delim = i == delimMax ? "" : ", "; - - items.push(GripArrayItem(Object.assign({}, this.props, { - object: value, - delim: delim, - // Do not propagate title to array items reps - title: undefined - }))); - } catch (exc) { - items.push(GripArrayItem(Object.assign({}, this.props, { - object: exc, - delim: delim, - // Do not propagate title to array items reps - title: undefined - }))); - } - } - if (previewItems.length > max || gripLength > previewItems.length) { - let leftItemNum = gripLength - max > 0 ? gripLength - max : gripLength - previewItems.length; - items.push(Caption({ - object: this.safeObjectLink({}, leftItemNum + " more…") - })); - } - - return items; - }, - - safeObjectLink: function (config, ...children) { - if (this.props.objectLink) { - return this.props.objectLink(Object.assign({ - object: this.props.object - }, config), ...children); - } - - if (Object.keys(config).length === 0 && children.length === 1) { - return children[0]; - } - - return span(config, ...children); - }, - - render: wrapRender(function () { - let { - object, - mode = MODE.SHORT - } = this.props; - - let items; - let brackets; - let needSpace = function (space) { - return space ? { left: "[ ", right: " ]" } : { left: "[", right: "]" }; - }; - - if (mode === MODE.TINY) { - let objectLength = this.getLength(object); - let isEmpty = objectLength === 0; - items = [span({ className: "length" }, isEmpty ? "" : objectLength)]; - brackets = needSpace(false); - } else { - let max = mode === MODE.SHORT ? 3 : 10; - items = this.arrayIterator(object, max); - brackets = needSpace(items.length > 0); - } - - let title = this.getTitle(object); - - return span({ - className: "objectBox objectBox-array" }, title, this.safeObjectLink({ - className: "arrayLeftBracket" - }, brackets.left), ...items, this.safeObjectLink({ - className: "arrayRightBracket" - }, brackets.right), span({ - className: "arrayProperties", - role: "group" })); - }) - }); + return span({ + className: "objectBox objectBox-array" }, title, safeObjectLink(props, { + className: "arrayLeftBracket" + }, brackets.left), ...items, safeObjectLink(props, { + className: "arrayRightBracket" + }, brackets.right), span({ + className: "arrayProperties", + role: "group" })); + } /** * Renders array item. Individual values are separated by * a delimiter (a comma by default). */ - let GripArrayItem = React.createFactory(React.createClass({ - displayName: "GripArrayItem", + GripArrayItem.propTypes = { + delim: React.PropTypes.string, + object: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.number, React.PropTypes.string]).isRequired, + objectLink: React.PropTypes.func, + // @TODO Change this to Object.values once it's supported in Node's version of V8 + mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + provider: React.PropTypes.object, + onDOMNodeMouseOver: React.PropTypes.func, + onDOMNodeMouseOut: React.PropTypes.func, + onInspectIconClick: React.PropTypes.func + }; - propTypes: { - delim: React.PropTypes.string, - object: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.number, React.PropTypes.string]).isRequired, - objectLink: React.PropTypes.func, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - provider: React.PropTypes.object, - attachedActorIds: React.PropTypes.array, - onDOMNodeMouseOver: React.PropTypes.func, - onDOMNodeMouseOut: React.PropTypes.func, - onInspectIconClick: React.PropTypes.func - }, + function GripArrayItem(props) { + let { Rep } = __webpack_require__(2); + let { + delim + } = props; - render: function () { - let { Rep } = createFactories(__webpack_require__(2)); + return span({}, Rep(Object.assign({}, props, { + mode: MODE.TINY + })), delim); + } - return span({}, Rep(Object.assign({}, this.props, { - mode: MODE.TINY - })), this.props.delim); + function getLength(grip) { + if (!grip.preview) { + return 0; } - })); + + return grip.preview.length || grip.preview.childNodesLength || 0; + } + + function getTitle(props, object, context) { + if (props.mode === MODE.TINY) { + return ""; + } + + let title = props.title || object.class || "Array"; + return safeObjectLink(props, {}, title + " "); + } + + function getPreviewItems(grip) { + if (!grip.preview) { + return null; + } + + return grip.preview.items || grip.preview.childNodes || null; + } + + function arrayIterator(props, grip, max) { + let items = []; + const gripLength = getLength(grip); + + if (!gripLength) { + return items; + } + + const previewItems = getPreviewItems(grip); + if (!previewItems) { + return items; + } + + let delim; + // number of grip preview items is limited to 10, but we may have more + // items in grip-array. + let delimMax = gripLength > previewItems.length ? previewItems.length : previewItems.length - 1; + let provider = props.provider; + + for (let i = 0; i < previewItems.length && i < max; i++) { + try { + let itemGrip = previewItems[i]; + let value = provider ? provider.getValue(itemGrip) : itemGrip; + + delim = i == delimMax ? "" : ", "; + + items.push(GripArrayItem(Object.assign({}, props, { + object: value, + delim: delim, + // Do not propagate title to array items reps + title: undefined + }))); + } catch (exc) { + items.push(GripArrayItem(Object.assign({}, props, { + object: exc, + delim: delim, + // Do not propagate title to array items reps + title: undefined + }))); + } + } + if (previewItems.length > max || gripLength > previewItems.length) { + let leftItemNum = gripLength - max > 0 ? gripLength - max : gripLength - previewItems.length; + items.push(Caption({ + object: safeObjectLink(props, {}, leftItemNum + " more…") + })); + } + + return items; + } function supportsObject(grip, type) { if (!isGrip(grip)) { @@ -3335,8 +3060,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: GripArray, - supportsObject: supportsObject + rep: wrapRender(GripArray), + supportsObject }; /***/ }, @@ -3344,176 +3069,158 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { // Dependencies - const React = __webpack_require__(3); + const React = __webpack_require__(4); const { isGrip, + safeObjectLink, wrapRender - } = __webpack_require__(4); - const Caption = React.createFactory(__webpack_require__(12)); - const PropRep = React.createFactory(__webpack_require__(14)); + } = __webpack_require__(3); + const Caption = __webpack_require__(12); + const PropRep = __webpack_require__(14); const { MODE } = __webpack_require__(1); // Shortcuts const { span } = React.DOM; + /** * Renders an map. A map is represented by a list of its * entries enclosed in curly brackets. */ - const GripMap = React.createClass({ - displayName: "GripMap", + GripMap.propTypes = { + object: React.PropTypes.object, + // @TODO Change this to Object.values once it's supported in Node's version of V8 + mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), + objectLink: React.PropTypes.func, + isInterestingEntry: React.PropTypes.func, + onDOMNodeMouseOver: React.PropTypes.func, + onDOMNodeMouseOut: React.PropTypes.func, + onInspectIconClick: React.PropTypes.func, + title: React.PropTypes.string + }; - propTypes: { - object: React.PropTypes.object, - // @TODO Change this to Object.values once it's supported in Node's version of V8 - mode: React.PropTypes.oneOf(Object.keys(MODE).map(key => MODE[key])), - objectLink: React.PropTypes.func, - isInterestingEntry: React.PropTypes.func, - attachedActorIds: React.PropTypes.array, - onDOMNodeMouseOver: React.PropTypes.func, - onDOMNodeMouseOut: React.PropTypes.func, - onInspectIconClick: React.PropTypes.func, - title: React.PropTypes.string - }, + function GripMap(props) { + let object = props.object; + let propsArray = safeEntriesIterator(props, object, props.mode === MODE.LONG ? 10 : 3); - getTitle: function (object) { - let title = this.props.title || (object && object.class ? object.class : "Map"); - return this.safeObjectLink({}, title); - }, + if (props.mode === MODE.TINY) { + return span({ className: "objectBox objectBox-object" }, getTitle(props, object)); + } - safeEntriesIterator: function (object, max) { - max = typeof max === "undefined" ? 3 : max; - try { - return this.entriesIterator(object, max); - } catch (err) { - console.error(err); - } - return []; - }, + return span({ className: "objectBox objectBox-object" }, getTitle(props, object), safeObjectLink(props, { + className: "objectLeftBrace" + }, " { "), propsArray, safeObjectLink(props, { + className: "objectRightBrace" + }, " }")); + } - entriesIterator: function (object, max) { - // Entry filter. Show only interesting entries to the user. - let isInterestingEntry = this.props.isInterestingEntry || ((type, value) => { - return type == "boolean" || type == "number" || type == "string" && value.length != 0; - }); + function getTitle(props, object) { + let title = props.title || (object && object.class ? object.class : "Map"); + return safeObjectLink(props, {}, title); + } - let mapEntries = object.preview && object.preview.entries ? object.preview.entries : []; + function safeEntriesIterator(props, object, max) { + max = typeof max === "undefined" ? 3 : max; + try { + return entriesIterator(props, object, max); + } catch (err) { + console.error(err); + } + return []; + } - let indexes = this.getEntriesIndexes(mapEntries, max, isInterestingEntry); - if (indexes.length < max && indexes.length < mapEntries.length) { - // There are not enough entries yet, so we add uninteresting entries. - indexes = indexes.concat(this.getEntriesIndexes(mapEntries, max - indexes.length, (t, value, name) => { - return !isInterestingEntry(t, value, name); - })); - } + function entriesIterator(props, object, max) { + // Entry filter. Show only interesting entries to the user. + let isInterestingEntry = props.isInterestingEntry || ((type, value) => { + return type == "boolean" || type == "number" || type == "string" && value.length != 0; + }); - let entries = this.getEntries(mapEntries, indexes); - if (entries.length < mapEntries.length) { - // There are some undisplayed entries. Then display "more…". - entries.push(Caption({ - key: "more", - object: this.safeObjectLink({}, `${mapEntries.length - max} more…`) - })); - } + let mapEntries = object.preview && object.preview.entries ? object.preview.entries : []; - return entries; - }, + let indexes = getEntriesIndexes(mapEntries, max, isInterestingEntry); + if (indexes.length < max && indexes.length < mapEntries.length) { + // There are not enough entries yet, so we add uninteresting entries. + indexes = indexes.concat(getEntriesIndexes(mapEntries, max - indexes.length, (t, value, name) => { + return !isInterestingEntry(t, value, name); + })); + } - /** - * Get entries ordered by index. - * - * @param {Array} entries Entries array. - * @param {Array} indexes Indexes of entries. - * @return {Array} Array of PropRep. - */ - getEntries: function (entries, indexes) { - let { + let entries = getEntries(props, mapEntries, indexes); + if (entries.length < mapEntries.length) { + // There are some undisplayed entries. Then display "more…". + entries.push(Caption({ + key: "more", + object: safeObjectLink(props, {}, `${mapEntries.length - max} more…`) + })); + } + + return entries; + } + + /** + * Get entries ordered by index. + * + * @param {Object} props Component props. + * @param {Array} entries Entries array. + * @param {Array} indexes Indexes of entries. + * @return {Array} Array of PropRep. + */ + function getEntries(props, entries, indexes) { + let { + objectLink, + onDOMNodeMouseOver, + onDOMNodeMouseOut, + onInspectIconClick + } = props; + + // Make indexes ordered by ascending. + indexes.sort(function (a, b) { + return a - b; + }); + + return indexes.map((index, i) => { + let [key, entryValue] = entries[index]; + let value = entryValue.value !== undefined ? entryValue.value : entryValue; + + return PropRep({ + // key, + name: key, + equal: ": ", + object: value, + // Do not add a trailing comma on the last entry + // if there won't be a "more..." item. + delim: i < indexes.length - 1 || indexes.length < entries.length ? ", " : null, + mode: MODE.TINY, objectLink, - attachedActorIds, onDOMNodeMouseOver, onDOMNodeMouseOut, onInspectIconClick - } = this.props; - - // Make indexes ordered by ascending. - indexes.sort(function (a, b) { - return a - b; }); + }); + } - return indexes.map((index, i) => { - let [key, entryValue] = entries[index]; - let value = entryValue.value !== undefined ? entryValue.value : entryValue; + /** + * Get the indexes of entries in the map. + * + * @param {Array} entries Entries array. + * @param {Number} max The maximum length of indexes array. + * @param {Function} filter Filter the entry you want. + * @return {Array} Indexes of filtered entries in the map. + */ + function getEntriesIndexes(entries, max, filter) { + return entries.reduce((indexes, [key, entry], i) => { + if (indexes.length < max) { + let value = entry && entry.value !== undefined ? entry.value : entry; + // Type is specified in grip's "class" field and for primitive + // values use typeof. + let type = (value && value.class ? value.class : typeof value).toLowerCase(); - return PropRep({ - // key, - name: key, - equal: ": ", - object: value, - // Do not add a trailing comma on the last entry - // if there won't be a "more..." item. - delim: i < indexes.length - 1 || indexes.length < entries.length ? ", " : "", - mode: MODE.TINY, - objectLink, - attachedActorIds, - onDOMNodeMouseOver, - onDOMNodeMouseOut, - onInspectIconClick - }); - }); - }, - - /** - * Get the indexes of entries in the map. - * - * @param {Array} entries Entries array. - * @param {Number} max The maximum length of indexes array. - * @param {Function} filter Filter the entry you want. - * @return {Array} Indexes of filtered entries in the map. - */ - getEntriesIndexes: function (entries, max, filter) { - return entries.reduce((indexes, [key, entry], i) => { - if (indexes.length < max) { - let value = entry && entry.value !== undefined ? entry.value : entry; - // Type is specified in grip's "class" field and for primitive - // values use typeof. - let type = (value && value.class ? value.class : typeof value).toLowerCase(); - - if (filter(type, value, key)) { - indexes.push(i); - } + if (filter(type, value, key)) { + indexes.push(i); } - - return indexes; - }, []); - }, - - safeObjectLink: function (config, ...children) { - if (this.props.objectLink) { - return this.props.objectLink(Object.assign({ - object: this.props.object - }, config), ...children); } - if (Object.keys(config).length === 0 && children.length === 1) { - return children[0]; - } - - return span(config, ...children); - }, - - render: wrapRender(function () { - let object = this.props.object; - let propsArray = this.safeEntriesIterator(object, this.props.mode === MODE.LONG ? 10 : 3); - - if (this.props.mode === MODE.TINY) { - return span({ className: "objectBox objectBox-object" }, this.getTitle(object)); - } - - return span({ className: "objectBox objectBox-object" }, this.getTitle(object), this.safeObjectLink({ - className: "objectLeftBrace" - }, " { "), propsArray, this.safeObjectLink({ - className: "objectRightBrace" - }, " }")); - }) - }); + return indexes; + }, []); + } function supportsObject(grip, type) { if (!isGrip(grip)) { @@ -3524,8 +3231,8 @@ return /******/ (function(modules) { // webpackBootstrap // Exports from this module module.exports = { - rep: GripMap, - supportsObject: supportsObject + rep: wrapRender(GripMap), + supportsObject }; /***/ } diff --git a/devtools/client/shared/components/reps/test/mochitest/head.js b/devtools/client/shared/components/reps/test/mochitest/head.js index ecc45bddbe17..e2e567260430 100644 --- a/devtools/client/shared/components/reps/test/mochitest/head.js +++ b/devtools/client/shared/components/reps/test/mochitest/head.js @@ -69,7 +69,3 @@ function testRepRenderModes(modeTests, testName, componentUnderTest, gripStub, is(rendered.textContent, expectedOutput, message); }); } - -function getStubAttachedActorIds(gripStubs) { - return gripStubs.map(gripStub => gripStub.actor); -} diff --git a/devtools/client/shared/components/reps/test/mochitest/test_reps_array.html b/devtools/client/shared/components/reps/test/mochitest/test_reps_array.html index 187323d4813a..48bd69969b1c 100644 --- a/devtools/client/shared/components/reps/test/mochitest/test_reps_array.html +++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_array.html @@ -20,8 +20,12 @@ Test ArrayRep rep /* import-globals-from head.js */ window.onload = Task.async(function* () { - const { REPS, MODE } = browserRequire("devtools/client/shared/components/reps/reps"); - let { Rep, ArrayRep } = REPS; + const { + REPS, + MODE, + getRep, + } = browserRequire("devtools/client/shared/components/reps/reps"); + let { ArrayRep } = REPS; let componentUnderTest = ArrayRep; const maxLength = { @@ -52,9 +56,7 @@ window.onload = Task.async(function* () { function testBasic() { // Test that correct rep is chosen const stub = []; - const renderedRep = shallowRenderComponent(Rep, { object: stub }); - is(renderedRep.type, ArrayRep.rep, - `Rep correctly selects ${ArrayRep.rep.displayName}`); + is(getRep(stub), ArrayRep.rep, "Rep correctly selects Array Rep"); // Test rendering diff --git a/devtools/client/shared/components/reps/test/mochitest/test_reps_attribute.html b/devtools/client/shared/components/reps/test/mochitest/test_reps_attribute.html index e0cbd54a3e4c..e85d7fabc219 100644 --- a/devtools/client/shared/components/reps/test/mochitest/test_reps_attribute.html +++ b/devtools/client/shared/components/reps/test/mochitest/test_reps_attribute.html @@ -17,8 +17,11 @@ Test Attribute rep + + + + + + +Mozilla Bug 1348409 + +

+ Here's some text to search for: fhqwhgads! A hovercraft full of eels! +

+ +

+ +
+
+ + \ No newline at end of file From bbde9021e65e18a51c30ca383ebf9003684b6008 Mon Sep 17 00:00:00 2001 From: James Willcox Date: Thu, 20 Apr 2017 09:43:51 -0500 Subject: [PATCH 59/65] Bug 1358155 - Bump core ping version and docs r=frank MozReview-Commit-ID: 1h417verpc2 --HG-- extra : rebase_source : 293cbbf4c01c5535579ab5d3862a01ef4de50234 --- .../gecko/telemetry/pingbuilders/TelemetryCorePingBuilder.java | 2 +- toolkit/components/telemetry/docs/data/core-ping.rst | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCorePingBuilder.java b/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCorePingBuilder.java index 8acf10696fe5..633eae736fd7 100644 --- a/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCorePingBuilder.java +++ b/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCorePingBuilder.java @@ -46,7 +46,7 @@ public class TelemetryCorePingBuilder extends TelemetryPingBuilder { private static final String PREF_SEQ_COUNT = "telemetry-seqCount"; private static final String NAME = "core"; - private static final int VERSION_VALUE = 8; // For version history, see toolkit/components/telemetry/docs/core-ping.rst + private static final int VERSION_VALUE = 9; // For version history, see toolkit/components/telemetry/docs/core-ping.rst private static final String OS_VALUE = "Android"; private static final String ARCHITECTURE = "arch"; diff --git a/toolkit/components/telemetry/docs/data/core-ping.rst b/toolkit/components/telemetry/docs/data/core-ping.rst index cf5c99b9e80d..5ab06a4f7be5 100644 --- a/toolkit/components/telemetry/docs/data/core-ping.rst +++ b/toolkit/components/telemetry/docs/data/core-ping.rst @@ -27,7 +27,7 @@ Structure: .. code-block:: js { - "v": 7, // ping format version + "v": 9, // ping format version "clientId": , // client id, e.g. // "c641eacf-c30c-4171-b403-f077724e848a" "seq": , // running ping counter, e.g. 3 @@ -158,6 +158,7 @@ et al (e.g. "Tue, 01 Feb 2011 14:00:00 GMT"). Version history --------------- +* v9: changed ``arch`` to contain device arch rather than the one we built against * v8: added ``flashUsage`` * v7: added ``sessionCount`` & ``sessionDuration`` * v6: added ``searches`` From d01b51f856d8461864e20a48d0ae28e46c346d78 Mon Sep 17 00:00:00 2001 From: Kirk Steuber Date: Wed, 19 Apr 2017 11:34:02 -0700 Subject: [PATCH 60/65] Bug 1357865 - Correctly zero the size of an InternalAttr in nsAttrAndChildArray::AddAttrSlot r=bz MozReview-Commit-ID: Csd4MO3fGpN --HG-- extra : rebase_source : a4944796952934dd62bf5828adf3330e1b64dffd --- dom/base/nsAttrAndChildArray.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dom/base/nsAttrAndChildArray.cpp b/dom/base/nsAttrAndChildArray.cpp index 640ada1016d2..6971d24bef88 100644 --- a/dom/base/nsAttrAndChildArray.cpp +++ b/dom/base/nsAttrAndChildArray.cpp @@ -880,8 +880,7 @@ nsAttrAndChildArray::AddAttrSlot() } SetAttrSlotCount(slotCount + 1); - offset[0] = nullptr; - offset[1] = nullptr; + memset(static_cast(offset), 0, sizeof(InternalAttr)); return true; } From 194ea01503fa49c7cb847e964b0832d92f3840a1 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Wed, 19 Apr 2017 21:40:43 -0700 Subject: [PATCH 61/65] Bug 1357999 - Make CCov and JSDCov builds properly sortable in Treeherder r=dustin,jmaher MozReview-Commit-ID: DLzdTO7Ttfj --HG-- extra : rebase_source : b3c76f261dabdcd14807fe5238b03c178b572b36 --- taskcluster/ci/build/linux.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/taskcluster/ci/build/linux.yml b/taskcluster/ci/build/linux.yml index a3a216491faf..d6d9b196de86 100644 --- a/taskcluster/ci/build/linux.yml +++ b/taskcluster/ci/build/linux.yml @@ -303,7 +303,7 @@ linux64-jsdcov/opt: product: firefox job-name: linux64-jsdcov-opt treeherder: - platform: linux64/jsdcov + platform: linux64-jsdcov/opt symbol: tc(B) tier: 2 run-on-projects: [ ] @@ -329,7 +329,7 @@ linux64-ccov/opt: job-name: linux64-ccov-opt needs-sccache: false treeherder: - platform: linux64/ccov + platform: linux64-ccov/opt symbol: tc(B) tier: 2 run-on-projects: [ ] From ceb65c045e43c4523301ae02291298f246fd392b Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Thu, 20 Apr 2017 19:11:04 +0200 Subject: [PATCH 62/65] Backed out changeset 816a2cc1254a (bug 1347728) for failing xpcshell's test_blocklist_certificates.js on Windows r=backout --- services/common/blocklist-clients.js | 7 +------ .../tests/unit/test_blocklist_clients.js | 18 ++++++++---------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/services/common/blocklist-clients.js b/services/common/blocklist-clients.js index f0d3e0df6299..87f90945694e 100644 --- a/services/common/blocklist-clients.js +++ b/services/common/blocklist-clients.js @@ -102,13 +102,8 @@ class BlocklistClient { }); } - get identifier() { - return `${this.bucketName}/${this.collectionName}`; - } - get filename() { - const identifier = OS.Path.join(...this.identifier.split("/")); - return `${identifier}.json`; + return `${this.bucketName}/${this.collectionName}.json`; } /** diff --git a/services/common/tests/unit/test_blocklist_clients.js b/services/common/tests/unit/test_blocklist_clients.js index 7c9fe839ee2f..9fa1f0427c34 100644 --- a/services/common/tests/unit/test_blocklist_clients.js +++ b/services/common/tests/unit/test_blocklist_clients.js @@ -1,5 +1,7 @@ const { Constructor: CC } = Components; +const KEY_PROFILEDIR = "ProfD"; + Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://testing-common/httpd.js"); Cu.import("resource://gre/modules/Timer.jsm"); @@ -56,10 +58,9 @@ function* clear_state() { yield sqliteHandle.close(); } - // Remove JSON dumps folders in profile dir. - const dumpFile = OS.Path.join(OS.Constants.Path.profileDir, client.filename); - const folder = OS.Path.dirname(dumpFile); - yield OS.File.removeDir(folder, { ignoreAbsent: true }); + // Remove profile data. + const path = OS.Path.join(OS.Constants.Path.profileDir, client.filename); + yield OS.File.remove(path, { ignoreAbsent: true }); } } @@ -131,8 +132,7 @@ add_task(clear_state); add_task(function* test_list_is_written_to_file_in_profile() { for (let {client, testData} of gBlocklistClients) { - const filePath = OS.Path.join(OS.Constants.Path.profileDir, client.filename); - const profFile = new FileUtils.File(filePath); + const profFile = FileUtils.getFile(KEY_PROFILEDIR, client.filename.split("/")); strictEqual(profFile.exists(), false); yield client.maybeSync(2000, Date.now(), {loadDump: false}); @@ -157,8 +157,7 @@ add_task(clear_state); add_task(function* test_update_json_file_when_addons_has_changes() { for (let {client, testData} of gBlocklistClients) { yield client.maybeSync(2000, Date.now() - 1000, {loadDump: false}); - const filePath = OS.Path.join(OS.Constants.Path.profileDir, client.filename); - const profFile = new FileUtils.File(filePath); + const profFile = FileUtils.getFile(KEY_PROFILEDIR, client.filename.split("/")); const fileLastModified = profFile.lastModifiedTime = profFile.lastModifiedTime - 1000; const serverTime = Date.now(); @@ -193,8 +192,7 @@ add_task(clear_state); add_task(function* test_do_nothing_when_blocklist_is_up_to_date() { for (let {client} of gBlocklistClients) { yield client.maybeSync(2000, Date.now() - 1000, {loadDump: false}); - const filePath = OS.Path.join(OS.Constants.Path.profileDir, client.filename); - const profFile = new FileUtils.File(filePath); + const profFile = FileUtils.getFile(KEY_PROFILEDIR, client.filename.split("/")); const fileLastModified = profFile.lastModifiedTime = profFile.lastModifiedTime - 1000; const serverTime = Date.now(); From 24596064239b1a2f2fbd19ee6fe8a76ffcf1f3e7 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 20 Apr 2017 15:20:39 -0500 Subject: [PATCH 63/65] Bug 1341102 - Update Stylo expectations. r=me MozReview-Commit-ID: 9urOcnY0Ulz --HG-- extra : source : 06ab368e6c0223e7a37c806e0786939620cb3f52 --- layout/style/test/stylo-failures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/style/test/stylo-failures.md b/layout/style/test/stylo-failures.md index c415be748447..17795708bbf3 100644 --- a/layout/style/test/stylo-failures.md +++ b/layout/style/test/stylo-failures.md @@ -200,7 +200,7 @@ to mochitest command. * ... `-moz-repeating-` [298] * webkit-prefixed gradient functions servo/servo#15441 * test_value_storage.html `-webkit-gradient` [225] - * ... `-webkit-linear-gradient` [10] + * ... `-webkit-linear-gradient` [15] * moz-prefixed intrinsic width values bug 1355402 * test_box_size_keywords.html [16] * test_flexbox_flex_shorthand.html `-moz-fit-content` [4] From 2fce16d9d03134751aeb4026976bc198dcc9dff3 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Thu, 20 Apr 2017 13:20:47 -0700 Subject: [PATCH 64/65] Backed out changeset d20f6afea6f0 (bug 1348409) for android failures in test_no_find_showDialog.html a=backout MozReview-Commit-ID: Hq6Ebrk1OJ0 --HG-- extra : source : 732dd62950212183eb8c3351be00b17980547468 --- dom/base/nsGlobalWindow.cpp | 29 +++++- dom/tests/mochitest/bugs/mochitest.ini | 1 - .../bugs/test_no_find_showDialog.html | 92 ------------------- 3 files changed, 26 insertions(+), 96 deletions(-) delete mode 100644 dom/tests/mochitest/bugs/test_no_find_showDialog.html diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 3e3afb30540b..44fa0375de29 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -10067,8 +10067,6 @@ nsGlobalWindow::FindOuter(const nsAString& aString, bool aCaseSensitive, { MOZ_RELEASE_ASSERT(IsOuterWindow()); - Unused << aShowDialog; - if (Preferences::GetBool("dom.disable_window_find", false)) { aError.Throw(NS_ERROR_NOT_AVAILABLE); return false; @@ -10101,7 +10099,32 @@ nsGlobalWindow::FindOuter(const nsAString& aString, bool aCaseSensitive, framesFinder->SetCurrentSearchFrame(AsOuter()); } - if (aString.IsEmpty()) { + // The Find API does not accept empty strings. Launch the Find Dialog. + if (aString.IsEmpty() || aShowDialog) { + // See if the find dialog is already up using nsIWindowMediator + nsCOMPtr windowMediator = + do_GetService(NS_WINDOWMEDIATOR_CONTRACTID); + + nsCOMPtr findDialog; + + if (windowMediator) { + windowMediator->GetMostRecentWindow(u"findInPage", + getter_AddRefs(findDialog)); + } + + if (findDialog) { + // The Find dialog is already open, bring it to the top. + auto* piFindDialog = nsPIDOMWindowOuter::From(findDialog); + aError = piFindDialog->Focus(); + } else if (finder) { + // Open a Find dialog + nsCOMPtr dialog; + aError = OpenDialog(NS_LITERAL_STRING("chrome://global/content/finddialog.xul"), + NS_LITERAL_STRING("_blank"), + NS_LITERAL_STRING("chrome, resizable=no, dependent=yes"), + finder, getter_AddRefs(dialog)); + } + return false; } diff --git a/dom/tests/mochitest/bugs/mochitest.ini b/dom/tests/mochitest/bugs/mochitest.ini index 768943c47975..e0c71f857318 100644 --- a/dom/tests/mochitest/bugs/mochitest.ini +++ b/dom/tests/mochitest/bugs/mochitest.ini @@ -162,4 +162,3 @@ skip-if = toolkit == 'android' [test_bug1112040.html] [test_bug1160342_marquee.html] [test_bug1171215.html] -[test_no_find_showDialog.html] diff --git a/dom/tests/mochitest/bugs/test_no_find_showDialog.html b/dom/tests/mochitest/bugs/test_no_find_showDialog.html deleted file mode 100644 index bd61e7488c97..000000000000 --- a/dom/tests/mochitest/bugs/test_no_find_showDialog.html +++ /dev/null @@ -1,92 +0,0 @@ - - - - - Test for Bug 1348409 - - - - - - - -Mozilla Bug 1348409 - -

- Here's some text to search for: fhqwhgads! A hovercraft full of eels! -

- -

- -
-
- - \ No newline at end of file From 843c9ebd6080dad93abf23c00e574fdce786fdc5 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 20 Apr 2017 16:02:04 -0500 Subject: [PATCH 65/65] Bug 1341102 - Update Stylo expectations. r=me a=merge MozReview-Commit-ID: DRUlxaDebID --HG-- extra : source : 6acd711190fced8731a2aa1a1e699cae2b3331ae --- layout/style/test/stylo-failures.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/layout/style/test/stylo-failures.md b/layout/style/test/stylo-failures.md index 17795708bbf3..a838b215e382 100644 --- a/layout/style/test/stylo-failures.md +++ b/layout/style/test/stylo-failures.md @@ -200,7 +200,8 @@ to mochitest command. * ... `-moz-repeating-` [298] * webkit-prefixed gradient functions servo/servo#15441 * test_value_storage.html `-webkit-gradient` [225] - * ... `-webkit-linear-gradient` [15] + * ... `-webkit-linear-gradient` [10] + * ... `-webkit-repeating-linear-gradient` [5] * moz-prefixed intrinsic width values bug 1355402 * test_box_size_keywords.html [16] * test_flexbox_flex_shorthand.html `-moz-fit-content` [4]