/* static */ void nsFontFaceUtils::MarkDirtyForFontChange(nsIFrame* aSubtreeRoot, const gfxUserFontEntry* aFont) { AutoTArray<nsIFrame*, 4> subtrees; subtrees.AppendElement(aSubtreeRoot); nsIPresShell* ps = aSubtreeRoot->PresContext()->PresShell(); // check descendants, iterating over subtrees that may include // additional subtrees associated with placeholders do { nsIFrame* subtreeRoot = subtrees.ElementAt(subtrees.Length() - 1); subtrees.RemoveElementAt(subtrees.Length() - 1); // Check all descendants to see if they use the font AutoTArray<nsIFrame*, 32> stack; stack.AppendElement(subtreeRoot); do { nsIFrame* f = stack.ElementAt(stack.Length() - 1); stack.RemoveElementAt(stack.Length() - 1); // if this frame uses the font, mark its descendants dirty // and skip checking its children if (FrameUsesFont(f, aFont)) { ScheduleReflow(ps, f); } else { if (f->GetType() == nsGkAtoms::placeholderFrame) { nsIFrame* oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f); if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot, oof)) { // We have another distinct subtree we need to mark. subtrees.AppendElement(oof); } } nsIFrame::ChildListIterator lists(f); for (; !lists.IsDone(); lists.Next()) { nsFrameList::Enumerator childFrames(lists.CurrentList()); for (; !childFrames.AtEnd(); childFrames.Next()) { nsIFrame* kid = childFrames.get(); stack.AppendElement(kid); } } } } while (!stack.IsEmpty()); } while (!subtrees.IsEmpty()); }
/* static */ nsresult SharedSurfacesChild::Share(ImageContainer* aContainer, WebRenderLayerManager* aManager, wr::IpcResourceUpdateQueue& aResources, wr::ImageKey& aKey) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aContainer); MOZ_ASSERT(aManager); if (aContainer->IsAsync()) { return NS_ERROR_NOT_IMPLEMENTED; } AutoTArray<ImageContainer::OwningImage,4> images; aContainer->GetCurrentImages(&images); if (images.IsEmpty()) { return NS_ERROR_NOT_AVAILABLE; } RefPtr<gfx::SourceSurface> surface = images[0].mImage->GetAsSourceSurface(); if (!surface) { return NS_ERROR_NOT_IMPLEMENTED; } if (surface->GetType() != SurfaceType::DATA_SHARED) { return NS_ERROR_NOT_IMPLEMENTED; } auto sharedSurface = static_cast<SourceSurfaceSharedData*>(surface.get()); return Share(sharedSurface, aManager, aResources, aKey); }
void VideoSink::RenderVideoFrames(int32_t aMaxFrames, int64_t aClockTime, const TimeStamp& aClockTimeStamp) { AssertOwnerThread(); AutoTArray<RefPtr<MediaData>,16> frames; VideoQueue().GetFirstElements(aMaxFrames, &frames); if (frames.IsEmpty() || !mContainer) { return; } AutoTArray<ImageContainer::NonOwningImage,16> images; TimeStamp lastFrameTime; MediaSink::PlaybackParams params = mAudioSink->GetPlaybackParams(); for (uint32_t i = 0; i < frames.Length(); ++i) { VideoData* frame = frames[i]->As<VideoData>(); frame->mSentToCompositor = true; if (!frame->mImage || !frame->mImage->IsValid() || !frame->mImage->GetSize().width || !frame->mImage->GetSize().height) { continue; } int64_t frameTime = frame->mTime; if (frameTime < 0) { // Frame times before the start time are invalid; drop such frames continue; } TimeStamp t; if (aMaxFrames > 1) { MOZ_ASSERT(!aClockTimeStamp.IsNull()); int64_t delta = frame->mTime - aClockTime; t = aClockTimeStamp + TimeDuration::FromMicroseconds(delta / params.mPlaybackRate); if (!lastFrameTime.IsNull() && t <= lastFrameTime) { // Timestamps out of order; drop the new frame. In theory we should // probably replace the previous frame with the new frame if the // timestamps are equal, but this is a corrupt video file already so // never mind. continue; } lastFrameTime = t; } ImageContainer::NonOwningImage* img = images.AppendElement(); img->mTimeStamp = t; img->mImage = frame->mImage; img->mFrameID = frame->mFrameID; img->mProducerID = mProducerID; VSINK_LOG_V("playing video frame %lld (id=%x) (vq-queued=%i)", frame->mTime, frame->mFrameID, VideoQueue().GetSize()); } mContainer->SetCurrentFrames(frames[0]->As<VideoData>()->mDisplay, images); }
// // Builds the textual representation of a selector. Called by DOM 2 CSS // StyleRule:selectorText // void nsCSSSelector::ToString(nsAString& aString, CSSStyleSheet* aSheet, bool aAppend) const { if (!aAppend) aString.Truncate(); // selectors are linked from right-to-left, so the next selector in // the linked list actually precedes this one in the resulting string AutoTArray<const nsCSSSelector*, 8> stack; for (const nsCSSSelector *s = this; s; s = s->mNext) { stack.AppendElement(s); } while (!stack.IsEmpty()) { uint32_t index = stack.Length() - 1; const nsCSSSelector *s = stack.ElementAt(index); stack.RemoveElementAt(index); s->AppendToStringWithoutCombinators(aString, aSheet, false); // Append the combinator, if needed. if (!stack.IsEmpty()) { const nsCSSSelector *next = stack.ElementAt(index - 1); char16_t oper = s->mOperator; if (next->IsPseudoElement()) { NS_ASSERTION(oper == char16_t(':'), "improperly chained pseudo element"); } else { NS_ASSERTION(oper != char16_t(0), "compound selector without combinator"); aString.Append(char16_t(' ')); if (oper != char16_t(' ')) { aString.Append(oper); aString.Append(char16_t(' ')); } } } } }
NS_IMETHODIMP RDFContentSinkImpl::HandleEndElement(const char16_t *aName) { FlushText(); nsIRDFResource* resource; if (NS_FAILED(PopContext(resource, mState, mParseMode))) { // XXX parser didn't catch unmatched tags? if (MOZ_LOG_TEST(gLog, LogLevel::Warning)) { nsAutoString tagStr(aName); char* tagCStr = ToNewCString(tagStr); PR_LogPrint ("rdfxml: extra close tag '%s' at line %d", tagCStr, 0/*XXX fix me */); free(tagCStr); } return NS_ERROR_UNEXPECTED; // XXX } // If we've just popped a member or property element, _now_ is the // time to add that element to the graph. switch (mState) { case eRDFContentSinkState_InMemberElement: { nsCOMPtr<nsIRDFContainer> container; NS_NewRDFContainer(getter_AddRefs(container)); container->Init(mDataSource, GetContextElement(1)); container->AppendElement(resource); } break; case eRDFContentSinkState_InPropertyElement: { mDataSource->Assert(GetContextElement(1), GetContextElement(0), resource, true); } break; default: break; } if (mContextStack->IsEmpty()) mState = eRDFContentSinkState_InEpilog; NS_IF_RELEASE(resource); return NS_OK; }
already_AddRefed<InternalResponse> FetchDriver::BeginAndGetFilteredResponse(InternalResponse* aResponse, bool aFoundOpaqueRedirect) { MOZ_ASSERT(aResponse); AutoTArray<nsCString, 4> reqURLList; mRequest->GetURLListWithoutFragment(reqURLList); MOZ_ASSERT(!reqURLList.IsEmpty()); aResponse->SetURLList(reqURLList); RefPtr<InternalResponse> filteredResponse; if (aFoundOpaqueRedirect) { filteredResponse = aResponse->OpaqueRedirectResponse(); } else { switch (mRequest->GetResponseTainting()) { case LoadTainting::Basic: filteredResponse = aResponse->BasicResponse(); break; case LoadTainting::CORS: filteredResponse = aResponse->CORSResponse(); break; case LoadTainting::Opaque: { filteredResponse = aResponse->OpaqueResponse(); nsresult rv = filteredResponse->GeneratePaddingInfo(); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } break; } default: MOZ_CRASH("Unexpected case"); } } MOZ_ASSERT(filteredResponse); MOZ_ASSERT(mObserver); if (!ShouldCheckSRI(mRequest, filteredResponse)) { mObserver->OnResponseAvailable(filteredResponse); #ifdef DEBUG mResponseAvailableCalled = true; #endif } return filteredResponse.forget(); }
nsresult RDFContentSinkImpl::PopContext(nsIRDFResource *&aResource, RDFContentSinkState &aState, RDFContentSinkParseMode &aParseMode) { if ((nullptr == mContextStack) || (mContextStack->IsEmpty())) { return NS_ERROR_NULL_POINTER; } uint32_t i = mContextStack->Length() - 1; RDFContextStackElement &e = mContextStack->ElementAt(i); aResource = e.mResource; NS_IF_ADDREF(aResource); aState = e.mState; aParseMode = e.mParseMode; mContextStack->RemoveElementAt(i); return NS_OK; }
bool ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) { AutoTArray<ImageContainer::OwningImage,4> images; uint32_t generationCounter; aContainer->GetCurrentImages(&images, &generationCounter); if (mLastUpdateGenerationCounter == generationCounter) { return true; } mLastUpdateGenerationCounter = generationCounter; for (int32_t i = images.Length() - 1; i >= 0; --i) { if (!images[i].mImage->IsValid()) { // Don't try to update to an invalid image. images.RemoveElementAt(i); } } if (images.IsEmpty()) { // This can happen if a ClearAllImages raced with SetCurrentImages from // another thread and ClearImagesFromImageBridge ran after the // SetCurrentImages call but before UpdateImageClientNow. // This can also happen if all images in the list are invalid. // We return true because the caller would attempt to recreate the // ImageClient otherwise, and that isn't going to help. return true; } nsTArray<Buffer> newBuffers; AutoTArray<CompositableForwarder::TimedTextureClient,4> textures; for (auto& img : images) { Image* image = img.mImage; #ifdef MOZ_WIDGET_GONK if (image->GetFormat() == ImageFormat::OVERLAY_IMAGE) { OverlayImage* overlayImage = static_cast<OverlayImage*>(image); OverlaySource source; if (overlayImage->GetSidebandStream().IsValid()) { // Duplicate GonkNativeHandle::NhObj for ipc, // since ParamTraits<GonkNativeHandle>::Write() absorbs native_handle_t. RefPtr<GonkNativeHandle::NhObj> nhObj = overlayImage->GetSidebandStream().GetDupNhObj(); GonkNativeHandle handle(nhObj); if (!handle.IsValid()) { gfxWarning() << "ImageClientSingle::UpdateImage failed in GetDupNhObj"; return false; } source.handle() = OverlayHandle(handle); } else { source.handle() = OverlayHandle(overlayImage->GetOverlayId()); } source.size() = overlayImage->GetSize(); GetForwarder()->UseOverlaySource(this, source, image->GetPictureRect()); continue; } #endif RefPtr<TextureClient> texture = image->GetTextureClient(this); const bool hasTextureClient = !!texture; for (int32_t i = mBuffers.Length() - 1; i >= 0; --i) { if (mBuffers[i].mImageSerial == image->GetSerial()) { if (hasTextureClient) { MOZ_ASSERT(image->GetTextureClient(this) == mBuffers[i].mTextureClient); } else { texture = mBuffers[i].mTextureClient; } // Remove this element from mBuffers so mBuffers only contains // images that aren't present in 'images' mBuffers.RemoveElementAt(i); } } if (!texture) { // Slow path, we should not be hitting it very often and if we do it means // we are using an Image class that is not backed by textureClient and we // should fix it. if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image); const PlanarYCbCrData* data = ycbcr->GetData(); if (!data) { return false; } texture = TextureClient::CreateForYCbCr(GetForwarder(), data->mYSize, data->mCbCrSize, data->mStereoMode, TextureFlags::DEFAULT | mTextureFlags ); if (!texture) { return false; } TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY); if (!autoLock.Succeeded()) { return false; } bool status = UpdateYCbCrTextureClient(texture, *data); MOZ_ASSERT(status); if (!status) { return false; } } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE || image->GetFormat() == ImageFormat::EGLIMAGE) { gfx::IntSize size = image->GetSize(); if (image->GetFormat() == ImageFormat::EGLIMAGE) { EGLImageImage* typedImage = image->AsEGLImageImage(); texture = EGLImageTextureData::CreateTextureClient( typedImage, size, GetForwarder(), mTextureFlags); #ifdef MOZ_WIDGET_ANDROID } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) { SurfaceTextureImage* typedImage = image->AsSurfaceTextureImage(); texture = AndroidSurfaceTextureData::CreateTextureClient( typedImage->GetSurfaceTexture(), size, typedImage->GetOriginPos(), GetForwarder(), mTextureFlags ); #endif } else { MOZ_ASSERT(false, "Bad ImageFormat."); } } else { RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface(); MOZ_ASSERT(surface); texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(), BackendSelector::Content, mTextureFlags); if (!texture) { return false; } MOZ_ASSERT(texture->CanExposeDrawTarget()); if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) { return false; } { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = texture->BorrowDrawTarget(); if (!dt) { gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget"; return false; } MOZ_ASSERT(surface.get()); dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } texture->Unlock(); } } if (!texture || !AddTextureClient(texture)) { return false; } CompositableForwarder::TimedTextureClient* t = textures.AppendElement(); t->mTextureClient = texture; t->mTimeStamp = img.mTimeStamp; t->mPictureRect = image->GetPictureRect(); t->mFrameID = img.mFrameID; t->mProducerID = img.mProducerID; Buffer* newBuf = newBuffers.AppendElement(); newBuf->mImageSerial = image->GetSerial(); newBuf->mTextureClient = texture; texture->SyncWithObject(GetForwarder()->GetSyncObject()); } GetForwarder()->UseTextures(this, textures); for (auto& b : mBuffers) { RemoveTexture(b.mTextureClient); } mBuffers.SwapElements(newBuffers); return true; }
bool ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) { AutoTArray<ImageContainer::OwningImage,4> images; uint32_t generationCounter; aContainer->GetCurrentImages(&images, &generationCounter); if (mLastUpdateGenerationCounter == generationCounter) { return true; } mLastUpdateGenerationCounter = generationCounter; for (int32_t i = images.Length() - 1; i >= 0; --i) { if (!images[i].mImage->IsValid()) { // Don't try to update to an invalid image. images.RemoveElementAt(i); } } if (images.IsEmpty()) { // This can happen if a ClearAllImages raced with SetCurrentImages from // another thread and ClearImagesFromImageBridge ran after the // SetCurrentImages call but before UpdateImageClientNow. // This can also happen if all images in the list are invalid. // We return true because the caller would attempt to recreate the // ImageClient otherwise, and that isn't going to help. for (auto& b : mBuffers) { RemoveTexture(b.mTextureClient); } mBuffers.Clear(); return true; } nsTArray<Buffer> newBuffers; AutoTArray<CompositableForwarder::TimedTextureClient,4> textures; for (auto& img : images) { Image* image = img.mImage; RefPtr<TextureClient> texture = image->GetTextureClient(GetForwarder()); const bool hasTextureClient = !!texture; for (int32_t i = mBuffers.Length() - 1; i >= 0; --i) { if (mBuffers[i].mImageSerial == image->GetSerial()) { if (hasTextureClient) { MOZ_ASSERT(image->GetTextureClient(GetForwarder()) == mBuffers[i].mTextureClient); } else { texture = mBuffers[i].mTextureClient; } // Remove this element from mBuffers so mBuffers only contains // images that aren't present in 'images' mBuffers.RemoveElementAt(i); } } if (!texture) { // Slow path, we should not be hitting it very often and if we do it means // we are using an Image class that is not backed by textureClient and we // should fix it. texture = CreateTextureClientForImage(image, GetForwarder()); } if (!texture) { return false; } // We check if the texture's allocator is still open, since in between media // decoding a frame and adding it to the compositable, we could have // restarted the GPU process. if (!texture->GetAllocator()->IPCOpen()) { continue; } if (!AddTextureClient(texture)) { return false; } CompositableForwarder::TimedTextureClient* t = textures.AppendElement(); t->mTextureClient = texture; t->mTimeStamp = img.mTimeStamp; t->mPictureRect = image->GetPictureRect(); t->mFrameID = img.mFrameID; t->mProducerID = img.mProducerID; Buffer* newBuf = newBuffers.AppendElement(); newBuf->mImageSerial = image->GetSerial(); newBuf->mTextureClient = texture; texture->SyncWithObject(GetForwarder()->GetSyncObject()); } GetForwarder()->UseTextures(this, textures); for (auto& b : mBuffers) { RemoveTexture(b.mTextureClient); } mBuffers.SwapElements(newBuffers); return true; }
nsMenuFrame* nsMenuBarFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent) { uint32_t charCode; aKeyEvent->GetCharCode(&charCode); AutoTArray<uint32_t, 10> accessKeys; WidgetKeyboardEvent* nativeKeyEvent = aKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent(); if (nativeKeyEvent) { nativeKeyEvent->GetAccessKeyCandidates(accessKeys); } if (accessKeys.IsEmpty() && charCode) accessKeys.AppendElement(charCode); if (accessKeys.IsEmpty()) return nullptr; // no character was pressed so just return // Enumerate over our list of frames. auto insertion = PresContext()->PresShell()->FrameConstructor()-> GetInsertionPoint(GetContent(), nullptr); nsContainerFrame* immediateParent = insertion.mParentFrame; if (!immediateParent) immediateParent = this; // Find a most preferred accesskey which should be returned. nsIFrame* foundMenu = nullptr; size_t foundIndex = accessKeys.NoIndex; nsIFrame* currFrame = immediateParent->PrincipalChildList().FirstChild(); while (currFrame) { nsIContent* current = currFrame->GetContent(); // See if it's a menu item. if (nsXULPopupManager::IsValidMenuItem(current, false)) { // Get the shortcut attribute. nsAutoString shortcutKey; current->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, shortcutKey); if (!shortcutKey.IsEmpty()) { ToLowerCase(shortcutKey); const char16_t* start = shortcutKey.BeginReading(); const char16_t* end = shortcutKey.EndReading(); uint32_t ch = UTF16CharEnumerator::NextChar(&start, end); size_t index = accessKeys.IndexOf(ch); if (index != accessKeys.NoIndex && (foundIndex == accessKeys.NoIndex || index < foundIndex)) { foundMenu = currFrame; foundIndex = index; } } } currFrame = currFrame->GetNextSibling(); } if (foundMenu) { return do_QueryFrame(foundMenu); } // didn't find a matching menu item #ifdef XP_WIN // behavior on Windows - this item is on the menu bar, beep and deactivate the menu bar if (mIsActive) { nsCOMPtr<nsISound> soundInterface = do_CreateInstance("@mozilla.org/sound;1"); if (soundInterface) soundInterface->Beep(); } nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); if (pm) { nsIFrame* popup = pm->GetTopPopup(ePopupTypeAny); if (popup) pm->HidePopup(popup->GetContent(), true, true, true, false); } SetCurrentMenuItem(nullptr); SetActive(false); #endif // #ifdef XP_WIN return nullptr; }
void VideoFrameContainer::SetCurrentFrames(const VideoSegment& aSegment) { if (aSegment.IsEmpty()) { return; } MutexAutoLock lock(mMutex); // Collect any new frames produced in this iteration. AutoTArray<ImageContainer::NonOwningImage,4> newImages; PrincipalHandle lastPrincipalHandle = PRINCIPAL_HANDLE_NONE; VideoSegment::ConstChunkIterator iter(aSegment); while (!iter.IsEnded()) { VideoChunk chunk = *iter; const VideoFrame* frame = &chunk.mFrame; if (*frame == mLastPlayedVideoFrame) { iter.Next(); continue; } Image* image = frame->GetImage(); CONTAINER_LOG(LogLevel::Verbose, ("VideoFrameContainer %p writing video frame %p (%d x %d)", this, image, frame->GetIntrinsicSize().width, frame->GetIntrinsicSize().height)); if (frame->GetForceBlack()) { if (!mBlackImage) { mBlackImage = GetImageContainer()->CreatePlanarYCbCrImage(); if (mBlackImage) { // Sets the image to a single black pixel, which will be scaled to // fill the rendered size. SetImageToBlackPixel(mBlackImage->AsPlanarYCbCrImage()); } } if (mBlackImage) { image = mBlackImage; } } // Don't append null image to the newImages. if (!image) { iter.Next(); continue; } newImages.AppendElement(ImageContainer::NonOwningImage(image, chunk.mTimeStamp)); lastPrincipalHandle = chunk.GetPrincipalHandle(); mLastPlayedVideoFrame = *frame; iter.Next(); } // Don't update if there are no changes. if (newImages.IsEmpty()) { return; } AutoTArray<ImageContainer::NonOwningImage,4> images; bool principalHandleChanged = lastPrincipalHandle != PRINCIPAL_HANDLE_NONE && lastPrincipalHandle != GetLastPrincipalHandleLocked(); // Add the frames from this iteration. for (auto& image : newImages) { image.mFrameID = NewFrameID(); images.AppendElement(image); } if (principalHandleChanged) { UpdatePrincipalHandleForFrameIDLocked(lastPrincipalHandle, newImages.LastElement().mFrameID); } SetCurrentFramesLocked(mLastPlayedVideoFrame.GetIntrinsicSize(), images); nsCOMPtr<nsIRunnable> event = new VideoFrameContainerInvalidateRunnable(this); mMainThread->Dispatch(event.forget()); images.ClearAndRetainStorage(); }
void CSSTransition::QueueEvents(const StickyTimeDuration& aActiveTime) { if (!mOwningElement.IsSet()) { return; } nsPresContext* presContext = mOwningElement.GetPresContext(); if (!presContext) { return; } static constexpr StickyTimeDuration zeroDuration = StickyTimeDuration(); TransitionPhase currentPhase; StickyTimeDuration intervalStartTime; StickyTimeDuration intervalEndTime; if (!mEffect) { currentPhase = GetAnimationPhaseWithoutEffect<TransitionPhase>(*this); } else { ComputedTiming computedTiming = mEffect->GetComputedTiming(); currentPhase = static_cast<TransitionPhase>(computedTiming.mPhase); intervalStartTime = std::max(std::min(StickyTimeDuration(-mEffect->SpecifiedTiming().Delay()), computedTiming.mActiveDuration), zeroDuration); intervalEndTime = std::max(std::min((EffectEnd() - mEffect->SpecifiedTiming().Delay()), computedTiming.mActiveDuration), zeroDuration); } // TimeStamps to use for ordering the events when they are dispatched. We // use a TimeStamp so we can compare events produced by different elements, // perhaps even with different timelines. // The zero timestamp is for transitionrun events where we ignore the delay // for the purpose of ordering events. TimeStamp zeroTimeStamp = AnimationTimeToTimeStamp(zeroDuration); TimeStamp startTimeStamp = ElapsedTimeToTimeStamp(intervalStartTime); TimeStamp endTimeStamp = ElapsedTimeToTimeStamp(intervalEndTime); if (mPendingState != PendingState::NotPending && (mPreviousTransitionPhase == TransitionPhase::Idle || mPreviousTransitionPhase == TransitionPhase::Pending)) { currentPhase = TransitionPhase::Pending; } AutoTArray<AnimationEventInfo, 3> events; auto appendTransitionEvent = [&](EventMessage aMessage, const StickyTimeDuration& aElapsedTime, const TimeStamp& aTimeStamp) { double elapsedTime = aElapsedTime.ToSeconds(); if (aMessage == eTransitionCancel) { elapsedTime = nsRFPService::ReduceTimePrecisionAsSecs(elapsedTime); } events.AppendElement(AnimationEventInfo(TransitionProperty(), mOwningElement.Target(), aMessage, elapsedTime, aTimeStamp, this)); }; // Handle cancel events first if ((mPreviousTransitionPhase != TransitionPhase::Idle && mPreviousTransitionPhase != TransitionPhase::After) && currentPhase == TransitionPhase::Idle) { TimeStamp activeTimeStamp = ElapsedTimeToTimeStamp(aActiveTime); appendTransitionEvent(eTransitionCancel, aActiveTime, activeTimeStamp); } // All other events switch (mPreviousTransitionPhase) { case TransitionPhase::Idle: if (currentPhase == TransitionPhase::Pending || currentPhase == TransitionPhase::Before) { appendTransitionEvent(eTransitionRun, intervalStartTime, zeroTimeStamp); } else if (currentPhase == TransitionPhase::Active) { appendTransitionEvent(eTransitionRun, intervalStartTime, zeroTimeStamp); appendTransitionEvent(eTransitionStart, intervalStartTime, startTimeStamp); } else if (currentPhase == TransitionPhase::After) { appendTransitionEvent(eTransitionRun, intervalStartTime, zeroTimeStamp); appendTransitionEvent(eTransitionStart, intervalStartTime, startTimeStamp); appendTransitionEvent(eTransitionEnd, intervalEndTime, endTimeStamp); } break; case TransitionPhase::Pending: case TransitionPhase::Before: if (currentPhase == TransitionPhase::Active) { appendTransitionEvent(eTransitionStart, intervalStartTime, startTimeStamp); } else if (currentPhase == TransitionPhase::After) { appendTransitionEvent(eTransitionStart, intervalStartTime, startTimeStamp); appendTransitionEvent(eTransitionEnd, intervalEndTime, endTimeStamp); } break; case TransitionPhase::Active: if (currentPhase == TransitionPhase::After) { appendTransitionEvent(eTransitionEnd, intervalEndTime, endTimeStamp); } else if (currentPhase == TransitionPhase::Before) { appendTransitionEvent(eTransitionEnd, intervalStartTime, startTimeStamp); } break; case TransitionPhase::After: if (currentPhase == TransitionPhase::Active) { appendTransitionEvent(eTransitionStart, intervalEndTime, startTimeStamp); } else if (currentPhase == TransitionPhase::Before) { appendTransitionEvent(eTransitionStart, intervalEndTime, startTimeStamp); appendTransitionEvent(eTransitionEnd, intervalStartTime, endTimeStamp); } break; } mPreviousTransitionPhase = currentPhase; if (!events.IsEmpty()) { presContext->AnimationEventDispatcher()->QueueEvents(Move(events)); } }
bool IsInterfaceEqualToOrInheritedFrom(REFIID aInterface, REFIID aFrom, unsigned long aVtableIndexHint) { if (aInterface == aFrom) { return true; } // We expect this array to be length 1 but that is not guaranteed by the API. AutoTArray<RefPtr<ITypeInfo>, 1> typeInfos; // Grab aInterface's ITypeInfo so that we may obtain information about its // inheritance hierarchy. RefPtr<ITypeInfo> typeInfo; if (RegisteredProxy::Find(aInterface, getter_AddRefs(typeInfo))) { typeInfos.AppendElement(Move(typeInfo)); } /** * The main loop of this function searches the hierarchy of aInterface's * parent interfaces, searching for aFrom. */ while (!typeInfos.IsEmpty()) { RefPtr<ITypeInfo> curTypeInfo(Move(typeInfos.LastElement())); typeInfos.RemoveElementAt(typeInfos.Length() - 1); TYPEATTR* typeAttr = nullptr; HRESULT hr = curTypeInfo->GetTypeAttr(&typeAttr); if (FAILED(hr)) { break; } bool isFromParentVtable = IsVtableIndexFromParentInterface(typeAttr, aVtableIndexHint); WORD numParentInterfaces = typeAttr->cImplTypes; curTypeInfo->ReleaseTypeAttr(typeAttr); typeAttr = nullptr; if (!isFromParentVtable) { // The vtable index cannot belong to this interface (otherwise the IIDs // would already have matched and we would have returned true). Since we // now also know that the vtable index cannot possibly be contained inside // curTypeInfo's parent interface, there is no point searching any further // up the hierarchy from here. OTOH we still should check any remaining // entries that are still in the typeInfos array, so we continue. continue; } for (WORD i = 0; i < numParentInterfaces; ++i) { HREFTYPE refCookie; hr = curTypeInfo->GetRefTypeOfImplType(i, &refCookie); if (FAILED(hr)) { continue; } RefPtr<ITypeInfo> nextTypeInfo; hr = curTypeInfo->GetRefTypeInfo(refCookie, getter_AddRefs(nextTypeInfo)); if (FAILED(hr)) { continue; } hr = nextTypeInfo->GetTypeAttr(&typeAttr); if (FAILED(hr)) { continue; } IID nextIid = typeAttr->guid; nextTypeInfo->ReleaseTypeAttr(typeAttr); typeAttr = nullptr; if (nextIid == aFrom) { return true; } typeInfos.AppendElement(Move(nextTypeInfo)); } } return false; }