bool CompositorPendingAnimations::startPendingAnimations() { bool startedSynchronizedOnCompositor = false; for (size_t i = 0; i < m_pending.size(); ++i) { if (!m_pending[i]->hasActiveAnimationsOnCompositor() && m_pending[i]->maybeStartAnimationOnCompositor() && !m_pending[i]->hasStartTime()) startedSynchronizedOnCompositor = true; } // If any synchronized animations were started on the compositor, all // remaning synchronized animations need to wait for the synchronized // start time. Otherwise they may start immediately. if (startedSynchronizedOnCompositor) { for (size_t i = 0; i < m_pending.size(); ++i) { if (!m_pending[i]->hasStartTime()) { m_waitingForCompositorAnimationStart.append(m_pending[i]); } } } else { for (size_t i = 0; i < m_pending.size(); ++i) { if (!m_pending[i]->hasStartTime()) { m_pending[i]->setStartTime(m_pending[i]->timeline()->currentTime()); m_pending[i]->update(AnimationPlayer::UpdateOnDemand); } } } m_pending.clear(); if (startedSynchronizedOnCompositor || m_waitingForCompositorAnimationStart.isEmpty()) return !m_waitingForCompositorAnimationStart.isEmpty(); // Check if we're still waiting for any compositor animations to start. for (size_t i = 0; i < m_waitingForCompositorAnimationStart.size(); ++i) { if (m_waitingForCompositorAnimationStart[i].get()->hasActiveAnimationsOnCompositor()) return true; } // If not, go ahead and start any animations that were waiting. notifyCompositorAnimationStarted(monotonicallyIncreasingTime()); return false; }
void HTMLResourcePreloader::preload(PassOwnPtr<PreloadRequest> preload, const NetworkHintsInterface& networkHintsInterface) { if (preload->isPreconnect()) { preconnectHost(preload.get(), networkHintsInterface); return; } // TODO(yoichio): Should preload if document is imported. if (!m_document->loader()) return; FetchRequest request = preload->resourceRequest(m_document); // TODO(dgozman): This check should go to HTMLPreloadScanner, but this requires // making Document::completeURLWithOverride logic to be statically accessible. if (request.url().protocolIsData()) return; if (preload->resourceType() == Resource::Script || preload->resourceType() == Resource::CSSStyleSheet || preload->resourceType() == Resource::ImportResource) request.setCharset(preload->charset().isEmpty() ? m_document->characterSet().string() : preload->charset()); request.setForPreload(true); int duration = static_cast<int>(1000 * (monotonicallyIncreasingTime() - preload->discoveryTime())); DEFINE_STATIC_LOCAL(CustomCountHistogram, preloadDelayHistogram, ("WebCore.PreloadDelayMs", 0, 2000, 20)); preloadDelayHistogram.count(duration); m_document->loader()->startPreload(preload->resourceType(), request); }
LinkHighlight::LinkHighlight(Node* node, WebViewImpl* owningWebViewImpl) : m_node(node) , m_owningWebViewImpl(owningWebViewImpl) , m_currentGraphicsLayer(0) , m_usingNonCompositedContentHost(false) , m_geometryNeedsUpdate(false) , m_isAnimating(false) , m_startTime(monotonicallyIncreasingTime()) { ASSERT(m_node); ASSERT(owningWebViewImpl); WebCompositorSupport* compositorSupport = Platform::current()->compositorSupport(); m_contentLayer = adoptPtr(compositorSupport->createContentLayer(this)); m_clipLayer = adoptPtr(compositorSupport->createLayer()); m_clipLayer->setAnchorPoint(WebFloatPoint()); m_clipLayer->addChild(m_contentLayer->layer()); m_contentLayer->layer()->setAnimationDelegate(this); m_contentLayer->layer()->setDrawsContent(true); m_contentLayer->layer()->setOpacity(1); m_geometryNeedsUpdate = true; updateGeometry(); }
void DocumentLoader::cancelLoadAfterXFrameOptionsOrCSPDenied(const ResourceResponse& response) { InspectorInstrumentation::continueAfterXFrameOptionsDenied(m_frame, this, mainResourceIdentifier(), response, m_mainResource.get()); setWasBlockedAfterXFrameOptionsOrCSP(); // Pretend that this was an empty HTTP 200 response. Don't reuse the // original URL for the empty page (https://crbug.com/622385). // // TODO(mkwst): Remove this once XFO moves to the browser. // https://crbug.com/555418. clearMainResourceHandle(); KURL blockedURL = SecurityOrigin::urlWithUniqueSecurityOrigin(); m_originalRequest.setURL(blockedURL); m_request.setURL(blockedURL); m_redirectChain.removeLast(); appendRedirect(blockedURL); m_response = ResourceResponse(blockedURL, "text/html", 0, nullAtom, String()); finishedLoading(monotonicallyIncreasingTime()); return; }
HIDGamepad::HIDGamepad(IOHIDDeviceRef hidDevice, unsigned index) : PlatformGamepad(index) , m_hidDevice(hidDevice) { m_connectTime = m_lastUpdateTime = monotonicallyIncreasingTime(); CFNumberRef cfVendorID = (CFNumberRef)IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDVendorIDKey)); CFNumberRef cfProductID = (CFNumberRef)IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDProductIDKey)); int vendorID, productID; CFNumberGetValue(cfVendorID, kCFNumberIntType, &vendorID); CFNumberGetValue(cfProductID, kCFNumberIntType, &productID); CFStringRef cfProductName = (CFStringRef)IOHIDDeviceGetProperty(hidDevice, CFSTR(kIOHIDProductKey)); String productName(cfProductName); // Currently the spec has no formatting for the id string. // This string formatting matches Firefox. m_id = String::format("%x-%x-%s", vendorID, productID, productName.utf8().data()); initElements(); }
bool CCSingleThreadProxy::doComposite() { ASSERT(!m_contextLost); { DebugScopedSetImplThread impl; double monotonicTime = monotonicallyIncreasingTime(); double wallClockTime = currentTime(); m_layerTreeHostImpl->animate(monotonicTime, wallClockTime); CCLayerTreeHostImpl::FrameData frame; m_layerTreeHostImpl->prepareToDraw(frame); m_layerTreeHostImpl->drawLayers(frame); } if (m_layerTreeHostImpl->isContextLost()) { m_contextLost = true; m_layerTreeHost->didLoseContext(); return false; } return true; }
void ResourceLoader::requestSynchronously(const ResourceRequest& request) { // downloadToFile is not supported for synchronous requests. DCHECK(!request.downloadToFile()); DCHECK(m_loader); DCHECK_EQ(request.priority(), ResourceLoadPriorityHighest); WrappedResourceRequest requestIn(request); WebURLResponse responseOut; WebURLError errorOut; WebData dataOut; int64_t encodedDataLength = WebURLLoaderClient::kUnknownEncodedDataLength; int64_t encodedBodyLength = 0; m_loader->loadSynchronously(requestIn, responseOut, errorOut, dataOut, encodedDataLength, encodedBodyLength); // A message dispatched while synchronously fetching the resource // can bring about the cancellation of this load. if (!m_loader) return; if (errorOut.reason) { didFail(errorOut, encodedDataLength, encodedBodyLength); return; } didReceiveResponse(responseOut); if (!m_loader) return; DCHECK_GE(responseOut.toResourceResponse().encodedBodyLength(), 0); // Follow the async case convention of not calling didReceiveData or // appending data to m_resource if the response body is empty. Copying the // empty buffer is a noop in most cases, but is destructive in the case of // a 304, where it will overwrite the cached data we should be reusing. if (dataOut.size()) { m_fetcher->didReceiveData(m_resource.get(), dataOut.data(), dataOut.size()); m_resource->setResourceBuffer(dataOut); } didFinishLoading(monotonicallyIncreasingTime(), encodedDataLength, encodedBodyLength); }
void ThreadedCompositor::DisplayRefreshMonitor::displayRefreshCallback() { bool shouldHandleDisplayRefreshNotification = false; { LockHolder locker(mutex()); shouldHandleDisplayRefreshNotification = isScheduled() && isPreviousFrameDone(); if (shouldHandleDisplayRefreshNotification) { setIsPreviousFrameDone(false); setMonotonicAnimationStartTime(monotonicallyIncreasingTime()); } } if (shouldHandleDisplayRefreshNotification) DisplayRefreshMonitor::handleDisplayRefreshedNotificationOnMainThread(this); if (m_compositor) { if (m_compositor->m_clientRendersNextFrame.compareExchangeStrong(true, false)) m_compositor->m_scene->renderNextFrame(); if (m_compositor->m_coordinateUpdateCompletionWithClient.compareExchangeStrong(true, false)) m_compositor->m_compositingRunLoop->updateCompleted(); } }
void CCThreadProxy::scheduledActionDrawAndSwap() { TRACE_EVENT("CCThreadProxy::scheduledActionDrawAndSwap", this, 0); ASSERT(isImplThread()); if (!m_layerTreeHostImpl) return; // FIXME: compute the frame display time more intelligently double monotonicTime = monotonicallyIncreasingTime(); double wallClockTime = currentTime(); m_inputHandlerOnImplThread->willDraw(monotonicTime); m_layerTreeHostImpl->animate(monotonicTime, wallClockTime); m_layerTreeHostImpl->drawLayers(); // Check for a pending compositeAndReadback. if (m_readbackRequestOnImplThread) { m_layerTreeHostImpl->readback(m_readbackRequestOnImplThread->pixels, m_readbackRequestOnImplThread->rect); m_readbackRequestOnImplThread->success = !m_layerTreeHostImpl->isContextLost(); m_readbackRequestOnImplThread->completion.signal(); m_readbackRequestOnImplThread = 0; } m_layerTreeHostImpl->swapBuffers(); // Process any finish request if (m_finishAllRenderingCompletionEventOnImplThread) { m_layerTreeHostImpl->finishAllRendering(); m_finishAllRenderingCompletionEventOnImplThread->signal(); m_finishAllRenderingCompletionEventOnImplThread = 0; } // Tell the main thread that the the newly-commited frame was drawn. if (m_nextFrameIsNewlyCommittedFrameOnImplThread) { m_nextFrameIsNewlyCommittedFrameOnImplThread = false; m_mainThreadProxy->postTask(createCCThreadTask(this, &CCThreadProxy::didCommitAndDrawFrame)); } }
void ResourceLoader::requestSynchronously() { OwnPtr<WebURLLoader> loader = adoptPtr(Platform::current()->createURLLoader()); ASSERT(loader); // downloadToFile is not supported for synchronous requests. ASSERT(!m_request.downloadToFile()); ResourcePtr<Resource> protectResource(m_resource); RELEASE_ASSERT(m_connectionState == ConnectionStateNew); m_connectionState = ConnectionStateStarted; WrappedResourceRequest requestIn(m_request); WebURLResponse responseOut; responseOut.initialize(); WebURLError errorOut; WebData dataOut; loader->loadSynchronously(requestIn, responseOut, errorOut, dataOut); if (errorOut.reason) { if (m_state == Terminated) { // A message dispatched while synchronously fetching the resource // can bring about the cancellation of this load. ASSERT(!m_resource); return; } didFail(0, errorOut); return; } didReceiveResponse(0, responseOut); if (m_state == Terminated) return; RefPtr<ResourceLoadInfo> resourceLoadInfo = responseOut.toResourceResponse().resourceLoadInfo(); int64_t encodedDataLength = resourceLoadInfo ? resourceLoadInfo->encodedDataLength : WebURLLoaderClient::kUnknownEncodedDataLength; m_fetcher->didReceiveData(m_resource, dataOut.data(), dataOut.size(), encodedDataLength); m_resource->setResourceBuffer(dataOut); didFinishLoading(0, monotonicallyIncreasingTime(), encodedDataLength); }
void AnimationBase::freezeAtTime(double t) { if (!m_compAnim) return; if (!m_startTime) { // If we haven't started yet, make it as if we started. LOG(Animations, "%p AnimationState %s -> StartWaitResponse", this, nameForState(m_animState)); m_animState = AnimationStateStartWaitResponse; onAnimationStartResponse(monotonicallyIncreasingTime()); } ASSERT(m_startTime); // if m_startTime is zero, we haven't started yet, so we'll get a bad pause time. if (t <= m_animation->delay()) m_pauseTime = m_startTime; else m_pauseTime = m_startTime + t - m_animation->delay(); #if USE(ACCELERATED_COMPOSITING) if (m_object && m_object->isComposited()) toRenderBoxModelObject(m_object)->suspendAnimations(m_pauseTime); #endif }
MouseEvent* MouseEvent::create(const AtomicString& eventType, AbstractView* view, Event* underlyingEvent, SimulatedClickCreationScope creationScope) { PlatformEvent::Modifiers modifiers = PlatformEvent::NoModifiers; if (UIEventWithKeyState* keyStateEvent = findEventWithKeyState(underlyingEvent)) { modifiers = keyStateEvent->modifiers(); } PlatformMouseEvent::SyntheticEventType syntheticType = PlatformMouseEvent::Positionless; int screenX = 0; int screenY = 0; if (underlyingEvent && underlyingEvent->isMouseEvent()) { syntheticType = PlatformMouseEvent::RealOrIndistinguishable; MouseEvent* mouseEvent = toMouseEvent(underlyingEvent); screenX = mouseEvent->screenX(); screenY = mouseEvent->screenY(); } double timestamp = underlyingEvent ? underlyingEvent->platformTimeStamp() : monotonicallyIncreasingTime(); MouseEvent* createdEvent = MouseEvent::create( eventType, true, true, view, 0, screenX, screenY, 0, 0, 0, 0, modifiers, 0, 0, nullptr, timestamp, syntheticType, String(), nullptr); createdEvent->setTrusted(creationScope == SimulatedClickCreationScope::FromUserAgent); createdEvent->setUnderlyingEvent(underlyingEvent); if (syntheticType == PlatformMouseEvent::RealOrIndistinguishable) { MouseEvent* mouseEvent = toMouseEvent(createdEvent->underlyingEvent()); createdEvent->initCoordinates(mouseEvent->clientX(), mouseEvent->clientY()); } return createdEvent; }
void SVGImageChromeClient::animationTimerFired(Timer<SVGImageChromeClient>*) { if (!m_image) return; // serviceScriptedAnimations runs requestAnimationFrame callbacks, but SVG // images can't have any so we assert there's no script. ScriptForbiddenScope forbidScript; // As neither SVGImage nor this chrome client object are on the Oilpan heap, // this object's reference to the SVGImage will not be traced should a GC // strike below. Hence, we must ensure that they both remain alive for // duration of this call. // // This is cannot arise non-Oilpan as an ImageResource is an owned object // and will be promptly released along with its (SVG)Image..and everything // below, including this object and its timer. For code simplicity, the // object protection isn't made the conditional on Oilpan. // // FIXME: Oilpan: move this and other ChromeClients to the Oilpan heap // to render this protection redundant. RefPtr<SVGImage> protect(m_image); m_image->frameView()->page()->animator().serviceScriptedAnimations(monotonicallyIncreasingTime()); m_image->frameView()->updateAllLifecyclePhases(); }
int JPEGImageEncoder::progressiveEncodeRowsJpegHelper(JPEGImageEncoderState* encoderState, unsigned char* data, int currentRowsCompleted, const double SlackBeforeDeadline, double deadlineSeconds) { JPEGImageEncoderStateImpl* encoderStateImpl = static_cast<JPEGImageEncoderStateImpl*>(encoderState); Vector<JSAMPLE> row(encoderStateImpl->cinfo()->image_width * encoderStateImpl->cinfo()->input_components); SET_JUMP_BUFFER(encoderStateImpl->cinfo(), ProgressiveEncodeFailed); const size_t pixelRowStride = encoderStateImpl->cinfo()->image_width * 4; unsigned char* pixels = data + pixelRowStride * currentRowsCompleted; while (encoderStateImpl->cinfo()->next_scanline < encoderStateImpl->cinfo()->image_height) { JSAMPLE* rowData = row.data(); RGBAtoRGB(pixels, encoderStateImpl->cinfo()->image_width, rowData); jpeg_write_scanlines(encoderStateImpl->cinfo(), &rowData, 1); pixels += pixelRowStride; currentRowsCompleted++; if (deadlineSeconds - SlackBeforeDeadline - monotonicallyIncreasingTime() <= 0) { return currentRowsCompleted; } } jpeg_finish_compress(encoderStateImpl->cinfo()); return currentRowsCompleted; }
bool CrossOriginPreflightResultCacheItem::parse(const ResourceResponse& response, String& errorDescription) { m_methods.clear(); if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Methods"), m_methods)) { errorDescription = "Cannot parse Access-Control-Allow-Methods response header field."; return false; } m_headers.clear(); if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Headers"), m_headers)) { errorDescription = "Cannot parse Access-Control-Allow-Headers response header field."; return false; } unsigned expiryDelta; if (parseAccessControlMaxAge(response.httpHeaderField("Access-Control-Max-Age"), expiryDelta)) { if (expiryDelta > maxPreflightCacheTimeoutSeconds) expiryDelta = maxPreflightCacheTimeoutSeconds; } else expiryDelta = defaultPreflightCacheTimeoutSeconds; m_absoluteExpiryTime = monotonicallyIncreasingTime() + expiryDelta; return true; }
void ValidationMessageClientImpl::checkAnchorStatus(Timer<ValidationMessageClientImpl>*) { ASSERT(m_currentAnchor); if (monotonicallyIncreasingTime() >= m_finishTime || !currentView()) { hideValidationMessage(*m_currentAnchor); return; } // Check the visibility of the element. // FIXME: Can we check invisibility by scrollable non-frame elements? IntRect newAnchorRect = currentView()->contentsToRootView(m_currentAnchor->pixelSnappedBoundingBox()); newAnchorRect = intersection(currentView()->convertToRootView(currentView()->boundsRect()), newAnchorRect); if (newAnchorRect.isEmpty()) { hideValidationMessage(*m_currentAnchor); return; } IntRect newAnchorRectInScreen = currentView()->hostWindow()->rootViewToScreen(newAnchorRect); if (newAnchorRectInScreen == m_lastAnchorRectInScreen && m_webView.pageScaleFactor() == m_lastPageScaleFactor) return; m_lastAnchorRectInScreen = newAnchorRectInScreen; m_lastPageScaleFactor = m_webView.pageScaleFactor(); m_webView.client()->moveValidationMessage(newAnchorRect); }
void SMILTimeContainer::setElapsed(SMILTime time) { // If the documment didn't begin yet, record a new start time, we'll seek to once its possible. if (!m_beginTime) { m_presetStartTime = time.value(); return; } if (m_beginTime) m_timer.stop(); double now = monotonicallyIncreasingTime(); m_beginTime = now - time.value(); if (m_pauseTime) { m_resumeTime = m_pauseTime = now; m_accumulatedActiveTime = time.value(); } else m_resumeTime = m_beginTime; #ifndef NDEBUG m_preventScheduledAnimationsChanges = true; #endif GroupedAnimationsMap::iterator end = m_scheduledAnimations.end(); for (GroupedAnimationsMap::iterator it = m_scheduledAnimations.begin(); it != end; ++it) { AnimationsVector* scheduled = it->value.get(); unsigned size = scheduled->size(); for (unsigned n = 0; n < size; n++) scheduled->at(n)->reset(); } #ifndef NDEBUG m_preventScheduledAnimationsChanges = false; #endif updateAnimations(time, true); }
bool GraphicsLayerTextureMapper::addAnimation(const KeyframeValueList& valueList, const FloatSize& boxSize, const Animation* anim, const String& keyframesName, double timeOffset) { ASSERT(!keyframesName.isEmpty()); if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2 || (valueList.property() != AnimatedPropertyWebkitTransform && valueList.property() != AnimatedPropertyOpacity)) return false; bool listsMatch = false; bool hasBigRotation; if (valueList.property() == AnimatedPropertyWebkitTransform) listsMatch = validateTransformOperations(valueList, hasBigRotation) >= 0; const double currentTime = monotonicallyIncreasingTime(); m_animations.add(TextureMapperAnimation(keyframesName, valueList, boxSize, anim, currentTime - timeOffset, listsMatch)); // m_animationStartTime is the time of the first real frame of animation, now or delayed by a negative offset. if (timeOffset > 0) m_animationStartTime = currentTime; else m_animationStartTime = currentTime - timeOffset; notifyChange(AnimationChange); notifyChange(AnimationStarted); return true; }
void LinkHighlight::startHighlightAnimationIfNeeded() { if (m_isAnimating) return; m_isAnimating = true; const float startOpacity = 1; // FIXME: Should duration be configurable? const float fadeDuration = 0.1f; const float minPreFadeDuration = 0.1f; m_contentLayer->layer()->setOpacity(startOpacity); WebCompositorSupport* compositorSupport = Platform::current()->compositorSupport(); OwnPtr<WebFloatAnimationCurve> curve = adoptPtr(compositorSupport->createFloatAnimationCurve()); curve->add(WebFloatKeyframe(0, startOpacity)); // Make sure we have displayed for at least minPreFadeDuration before starting to fade out. float extraDurationRequired = std::max(0.f, minPreFadeDuration - static_cast<float>(monotonicallyIncreasingTime() - m_startTime)); if (extraDurationRequired) curve->add(WebFloatKeyframe(extraDurationRequired, startOpacity)); // For layout tests we don't fade out. curve->add(WebFloatKeyframe(fadeDuration + extraDurationRequired, blink::layoutTestMode() ? startOpacity : 0)); OwnPtr<WebAnimation> animation = adoptPtr(compositorSupport->createAnimation(*curve, WebAnimation::TargetPropertyOpacity)); m_contentLayer->layer()->setDrawsContent(true); m_contentLayer->layer()->addAnimation(animation.leakPtr()); invalidate(); m_owningWebViewImpl->scheduleAnimation(); }
double AnimationControllerPrivate::beginAnimationUpdateTime() { if (m_beginAnimationUpdateTime == cBeginAnimationUpdateTimeNotSet) m_beginAnimationUpdateTime = monotonicallyIncreasingTime(); return m_beginAnimationUpdateTime; }
void BitmapImage::startAnimation(bool catchUpIfNecessary) { if (m_frameTimer || !shouldAnimate() || frameCount() <= 1) return; // If we aren't already animating, set now as the animation start time. const double time = monotonicallyIncreasingTime(); if (!m_desiredFrameStartTime) m_desiredFrameStartTime = time; // Don't advance the animation to an incomplete frame. size_t nextFrame = (m_currentFrame + 1) % frameCount(); if (!m_allDataReceived && !frameIsCompleteAtIndex(nextFrame)) return; // Don't advance past the last frame if we haven't decoded the whole image // yet and our repetition count is potentially unset. The repetition count // in a GIF can potentially come after all the rest of the image data, so // wait on it. if (!m_allDataReceived && repetitionCount(false) == cAnimationLoopOnce && m_currentFrame >= (frameCount() - 1)) return; // Determine time for next frame to start. By ignoring paint and timer lag // in this calculation, we make the animation appear to run at its desired // rate regardless of how fast it's being repainted. const double currentDuration = frameDurationAtIndex(m_currentFrame); m_desiredFrameStartTime += currentDuration; // When an animated image is more than five minutes out of date, the // user probably doesn't care about resyncing and we could burn a lot of // time looping through frames below. Just reset the timings. const double cAnimationResyncCutoff = 5 * 60; if ((time - m_desiredFrameStartTime) > cAnimationResyncCutoff) m_desiredFrameStartTime = time + currentDuration; // The image may load more slowly than it's supposed to animate, so that by // the time we reach the end of the first repetition, we're well behind. // Clamp the desired frame start time in this case, so that we don't skip // frames (or whole iterations) trying to "catch up". This is a tradeoff: // It guarantees users see the whole animation the second time through and // don't miss any repetitions, and is closer to what other browsers do; on // the other hand, it makes animations "less accurate" for pages that try to // sync an image and some other resource (e.g. audio), especially if users // switch tabs (and thus stop drawing the animation, which will pause it) // during that initial loop, then switch back later. if (nextFrame == 0 && m_repetitionsComplete == 0 && m_desiredFrameStartTime < time) m_desiredFrameStartTime = time; if (!catchUpIfNecessary || time < m_desiredFrameStartTime) { // Haven't yet reached time for next frame to start; delay until then. m_frameTimer = new Timer<BitmapImage>(this, &BitmapImage::advanceAnimation); m_frameTimer->startOneShot(std::max(m_desiredFrameStartTime - time, 0.)); } else { // We've already reached or passed the time for the next frame to start. // See if we've also passed the time for frames after that to start, in // case we need to skip some frames entirely. Remember not to advance // to an incomplete frame. for (size_t frameAfterNext = (nextFrame + 1) % frameCount(); frameIsCompleteAtIndex(frameAfterNext); frameAfterNext = (nextFrame + 1) % frameCount()) { // Should we skip the next frame? double frameAfterNextStartTime = m_desiredFrameStartTime + frameDurationAtIndex(nextFrame); if (time < frameAfterNextStartTime) break; // Yes; skip over it without notifying our observers. if (!internalAdvanceAnimation(true)) return; m_desiredFrameStartTime = frameAfterNextStartTime; nextFrame = frameAfterNext; } // Draw the next frame immediately. Note that m_desiredFrameStartTime // may be in the past, meaning the next time through this function we'll // kick off the next advancement sooner than this frame's duration would // suggest. if (internalAdvanceAnimation(false)) { // The image region has been marked dirty, but once we return to our // caller, draw() will clear it, and nothing will cause the // animation to advance again. We need to start the timer for the // next frame running, or the animation can hang. (Compare this // with when advanceAnimation() is called, and the region is dirtied // while draw() is not in the callstack, meaning draw() gets called // to update the region and thus startAnimation() is reached again.) // NOTE: For large images with slow or heavily-loaded systems, // throwing away data as we go (see destroyDecodedData()) means we // can spend so much time re-decoding data above that by the time we // reach here we're behind again. If we let startAnimation() run // the catch-up code again, we can get long delays without painting // as we race the timer, or even infinite recursion. In this // situation the best we can do is to simply change frames as fast // as possible, so force startAnimation() to set a zero-delay timer // and bail out if we're not caught up. startAnimation(false); } } }
void SpeechSynthesis::fireEvent(const AtomicString& type, SpeechSynthesisUtterance* utterance, unsigned long charIndex, const String& name) { utterance->dispatchEvent(SpeechSynthesisEvent::create(type, charIndex, (monotonicallyIncreasingTime() - utterance->startTime()), name)); }
void ProgressTracker::incrementProgress(unsigned long identifier, const char*, int length) { ProgressItem* item = m_progressItems.get(identifier); // FIXME: Can this ever happen? if (!item) return; RefPtr<Frame> frame = m_originatingProgressFrame; frame->loader().client().willChangeEstimatedProgress(); unsigned bytesReceived = length; double increment, percentOfRemainingBytes; long long remainingBytes, estimatedBytesForPendingRequests; item->bytesReceived += bytesReceived; if (item->bytesReceived > item->estimatedLength) { m_totalPageAndResourceBytesToLoad += ((item->bytesReceived * 2) - item->estimatedLength); item->estimatedLength = item->bytesReceived * 2; } int numPendingOrLoadingRequests = frame->loader().numPendingOrLoadingRequests(true); estimatedBytesForPendingRequests = progressItemDefaultEstimatedLength * numPendingOrLoadingRequests; remainingBytes = ((m_totalPageAndResourceBytesToLoad + estimatedBytesForPendingRequests) - m_totalBytesReceived); if (remainingBytes > 0) // Prevent divide by 0. percentOfRemainingBytes = (double)bytesReceived / (double)remainingBytes; else percentOfRemainingBytes = 1.0; // For documents that use WebCore's layout system, treat first layout as the half-way point. // FIXME: The hasHTMLView function is a sort of roundabout way of asking "do you use WebCore's layout system". bool useClampedMaxProgress = frame->loader().client().hasHTMLView() && !frame->loader().stateMachine()->firstLayoutDone(); double maxProgressValue = useClampedMaxProgress ? 0.5 : finalProgressValue; increment = (maxProgressValue - m_progressValue) * percentOfRemainingBytes; m_progressValue += increment; m_progressValue = min(m_progressValue, maxProgressValue); ASSERT(m_progressValue >= initialProgressValue); m_totalBytesReceived += bytesReceived; double now = monotonicallyIncreasingTime(); double notifiedProgressTimeDelta = now - m_lastNotifiedProgressTime; LOG(Progress, "Progress incremented (%p) - value %f, tracked frames %d", this, m_progressValue, m_numProgressTrackedFrames); double notificationProgressDelta = m_progressValue - m_lastNotifiedProgressValue; if ((notificationProgressDelta >= m_progressNotificationInterval || notifiedProgressTimeDelta >= m_progressNotificationTimeInterval) && m_numProgressTrackedFrames > 0) { if (!m_finalProgressChangedSent) { if (m_progressValue == 1) m_finalProgressChangedSent = true; frame->loader().client().postProgressEstimateChangedNotification(); m_lastNotifiedProgressValue = m_progressValue; m_lastNotifiedProgressTime = now; } } frame->loader().client().didChangeEstimatedProgress(); }
bool ScrollAnimationSmooth::updatePerAxisData(PerAxisData& data, ScrollGranularity granularity, float delta, float minScrollPosition, float maxScrollPosition) { if (!data.startTime || !delta || (delta < 0) != (data.desiredPosition - data.currentPosition < 0)) { data.desiredPosition = data.currentPosition; data.startTime = 0; } float newPosition = data.desiredPosition + delta; newPosition = std::max(std::min(newPosition, maxScrollPosition), minScrollPosition); if (newPosition == data.desiredPosition) return false; double animationTime, repeatMinimumSustainTime, attackTime, releaseTime, maximumCoastTime; Curve coastTimeCurve; getAnimationParametersForGranularity(granularity, animationTime, repeatMinimumSustainTime, attackTime, releaseTime, coastTimeCurve, maximumCoastTime); data.desiredPosition = newPosition; if (!data.startTime) data.attackTime = attackTime; data.animationTime = animationTime; data.releaseTime = releaseTime; // Prioritize our way out of over constraint. if (data.attackTime + data.releaseTime > data.animationTime) { if (data.releaseTime > data.animationTime) data.releaseTime = data.animationTime; data.attackTime = data.animationTime - data.releaseTime; } if (!data.startTime) { // FIXME: This should be the time from the event that got us here. data.startTime = monotonicallyIncreasingTime() - tickTime / 2; data.startPosition = data.currentPosition; data.lastAnimationTime = data.startTime; } data.startVelocity = data.currentVelocity; double remainingDelta = data.desiredPosition - data.currentPosition; double attackAreaLeft = 0; double deltaTime = data.lastAnimationTime - data.startTime; double attackTimeLeft = std::max(0., data.attackTime - deltaTime); double timeLeft = data.animationTime - deltaTime; double minTimeLeft = data.releaseTime + std::min(repeatMinimumSustainTime, data.animationTime - data.releaseTime - attackTimeLeft); if (timeLeft < minTimeLeft) { data.animationTime = deltaTime + minTimeLeft; timeLeft = minTimeLeft; } if (maximumCoastTime > (repeatMinimumSustainTime + releaseTime)) { double targetMaxCoastVelocity = data.visibleLength * .25 * frameRate; // This needs to be as minimal as possible while not being intrusive to page up/down. double minCoastDelta = data.visibleLength; if (fabs(remainingDelta) > minCoastDelta) { double maxCoastDelta = maximumCoastTime * targetMaxCoastVelocity; double coastFactor = std::min(1., (fabs(remainingDelta) - minCoastDelta) / (maxCoastDelta - minCoastDelta)); // We could play with the curve here - linear seems a little soft. Initial testing makes me want to feed into the sustain time more aggressively. double coastMinTimeLeft = std::min(maximumCoastTime, minTimeLeft + coastCurve(coastTimeCurve, coastFactor) * (maximumCoastTime - minTimeLeft)); if (double additionalTime = std::max(0., coastMinTimeLeft - minTimeLeft)) { double additionalReleaseTime = std::min(additionalTime, releaseTime / (releaseTime + repeatMinimumSustainTime) * additionalTime); data.releaseTime = releaseTime + additionalReleaseTime; data.animationTime = deltaTime + coastMinTimeLeft; timeLeft = coastMinTimeLeft; } } } double releaseTimeLeft = std::min(timeLeft, data.releaseTime); double sustainTimeLeft = std::max(0., timeLeft - releaseTimeLeft - attackTimeLeft); if (attackTimeLeft) { double attackSpot = deltaTime / data.attackTime; attackAreaLeft = attackArea(Curve::Cubic, attackSpot, 1) * data.attackTime; } double releaseSpot = (data.releaseTime - releaseTimeLeft) / data.releaseTime; double releaseAreaLeft = releaseArea(Curve::Cubic, releaseSpot, 1) * data.releaseTime; data.desiredVelocity = remainingDelta / (attackAreaLeft + sustainTimeLeft + releaseAreaLeft); data.releasePosition = data.desiredPosition - data.desiredVelocity * releaseAreaLeft; if (attackAreaLeft) data.attackPosition = data.startPosition + data.desiredVelocity * attackAreaLeft; else data.attackPosition = data.releasePosition - (data.animationTime - data.releaseTime - data.attackTime) * data.desiredVelocity; if (sustainTimeLeft) { double roundOff = data.releasePosition - ((attackAreaLeft ? data.attackPosition : data.currentPosition) + data.desiredVelocity * sustainTimeLeft); data.desiredVelocity += roundOff / sustainTimeLeft; } return true; }
void CCSingleThreadProxy::startPageScaleAnimation(const IntSize& targetPosition, bool useAnchor, float scale, double duration) { m_layerTreeHostImpl->startPageScaleAnimation(targetPosition, useAnchor, scale, monotonicallyIncreasingTime(), duration); }
void TimelineTimeConverter::reset() { m_startOffset = monotonicallyIncreasingTime() - currentTime(); }
SharedWorkerGlobalScope::SharedWorkerGlobalScope(const String& name, const KURL& url, const String& userAgent, SharedWorkerThread* thread, PassOwnPtrWillBeRawPtr<WorkerClients> workerClients) : WorkerGlobalScope(url, userAgent, thread, monotonicallyIncreasingTime(), workerClients) , m_name(name) { ScriptWrappable::init(this); }
void MainResourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce) { ASSERT(data); ASSERT(length != 0); ASSERT(!m_response.isNull()); #if USE(CFNETWORK) || PLATFORM(MAC) // Workaround for <rdar://problem/6060782> if (m_response.isNull()) { m_response = ResourceResponse(KURL(), "text/html", 0, String(), String()); if (DocumentLoader* documentLoader = frameLoader()->activeDocumentLoader()) documentLoader->setResponse(m_response); } #endif // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred. // See <rdar://problem/6304600> for more details. #if !USE(CF) ASSERT(!defersLoading()); #endif #if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 if (m_filter) { ASSERT(!wkFilterWasBlocked(m_filter)); const char* blockedData = wkFilterAddData(m_filter, data, &length); // If we don't have blockedData, that means we're still accumulating data if (!blockedData) { // Transition to committed state. ResourceLoader::didReceiveData("", 0, 0, false); return; } data = blockedData; encodedDataLength = -1; } #endif documentLoader()->applicationCacheHost()->mainResourceDataReceived(data, length, encodedDataLength, allAtOnce); // The additional processing can do anything including possibly removing the last // reference to this object; one example of this is 3266216. RefPtr<MainResourceLoader> protect(this); m_timeOfLastDataReceived = monotonicallyIncreasingTime(); ResourceLoader::didReceiveData(data, length, encodedDataLength, allAtOnce); #if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 if (WebFilterEvaluator *filter = m_filter) { // If we got here, it means we know if we were blocked or not. If we were blocked, we're // done loading the page altogether. Either way, we don't need the filter anymore. // Remove this->m_filter early so didFinishLoading doesn't see it. m_filter = 0; if (wkFilterWasBlocked(filter)) cancel(); wkFilterRelease(filter); } #endif }
void MainResourceLoader::didFinishLoading(double finishTime) { // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred. // See <rdar://problem/6304600> for more details. #if !USE(CF) ASSERT(shouldLoadAsEmptyDocument(frameLoader()->activeDocumentLoader()->url()) || !defersLoading() || InspectorInstrumentation::isDebuggerPaused(m_frame.get())); #endif // The additional processing can do anything including possibly removing the last // reference to this object. RefPtr<MainResourceLoader> protect(this); RefPtr<DocumentLoader> dl = documentLoader(); #if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 if (m_filter) { int length; const char* data = wkFilterDataComplete(m_filter, &length); WebFilterEvaluator *filter = m_filter; // Remove this->m_filter early so didReceiveData doesn't see it. m_filter = 0; if (data) didReceiveData(data, length, -1, false); wkFilterRelease(filter); } #endif if (m_loadingMultipartContent) dl->maybeFinishLoadingMultipartContent(); documentLoader()->timing()->setResponseEnd(finishTime ? finishTime : (m_timeOfLastDataReceived ? m_timeOfLastDataReceived : monotonicallyIncreasingTime())); documentLoader()->finishedLoading(); ResourceLoader::didFinishLoading(finishTime); dl->applicationCacheHost()->finishedLoadingMainResource(); }
void DocumentThreadableLoader::start(const ResourceRequest& request) { // Setting an outgoing referer is only supported in the async code path. DCHECK(m_async || request.httpReferrer().isEmpty()); m_sameOriginRequest = getSecurityOrigin()->canRequestNoSuborigin(request.url()); m_requestContext = request.requestContext(); m_redirectMode = request.fetchRedirectMode(); if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == DenyCrossOriginRequests) { InspectorInstrumentation:: documentThreadableLoaderFailedToStartLoadingForClient(m_document, m_client); ThreadableLoaderClient* client = m_client; clear(); client->didFail(ResourceError(errorDomainBlinkInternal, 0, request.url().getString(), "Cross origin requests are not supported.")); return; } m_requestStartedSeconds = monotonicallyIncreasingTime(); // Save any headers on the request here. If this request redirects // cross-origin, we cancel the old request create a new one, and copy these // headers. m_requestHeaders = request.httpHeaderFields(); // DocumentThreadableLoader is used by all javascript initiated fetch, so we // use this chance to record non-GET fetch script requests. However, this is // based on the following assumptions, so please be careful when adding // similar logic: // - ThreadableLoader is used as backend for all javascript initiated network // fetches. // - Note that ThreadableLoader is also used for non-network fetch such as // FileReaderLoader. However it emulates GET method so signal is not // recorded here. // - ThreadableLoader w/ non-GET request is only created from javascript // initiated fetch. // - Some non-script initiated fetches such as WorkerScriptLoader also use // ThreadableLoader, but they are guaranteed to use GET method. if (request.httpMethod() != HTTPNames::GET) { if (Page* page = m_document->page()) page->chromeClient().didObserveNonGetFetchFromScript(); } ResourceRequest newRequest(request); if (m_requestContext != WebURLRequest::RequestContextFetch) { // When the request context is not "fetch", |crossOriginRequestPolicy| // represents the fetch request mode, and |credentialsRequested| represents // the fetch credentials mode. So we set those flags here so that we can see // the correct request mode and credentials mode in the service worker's // fetch event handler. switch (m_options.crossOriginRequestPolicy) { case DenyCrossOriginRequests: newRequest.setFetchRequestMode( WebURLRequest::FetchRequestModeSameOrigin); break; case UseAccessControl: if (m_options.preflightPolicy == ForcePreflight) { newRequest.setFetchRequestMode( WebURLRequest::FetchRequestModeCORSWithForcedPreflight); } else { newRequest.setFetchRequestMode(WebURLRequest::FetchRequestModeCORS); } break; case AllowCrossOriginRequests: SECURITY_CHECK(IsNoCORSAllowedContext(m_requestContext, request.skipServiceWorker())); newRequest.setFetchRequestMode(WebURLRequest::FetchRequestModeNoCORS); break; } if (m_resourceLoaderOptions.allowCredentials == AllowStoredCredentials) { newRequest.setFetchCredentialsMode( WebURLRequest::FetchCredentialsModeInclude); } else { newRequest.setFetchCredentialsMode( WebURLRequest::FetchCredentialsModeSameOrigin); } } // We assume that ServiceWorker is skipped for sync requests and unsupported // protocol requests by content/ code. if (m_async && request.skipServiceWorker() == WebURLRequest::SkipServiceWorker::None && SchemeRegistry::shouldTreatURLSchemeAsAllowingServiceWorkers( request.url().protocol()) && m_document->fetcher()->isControlledByServiceWorker()) { if (newRequest.fetchRequestMode() == WebURLRequest::FetchRequestModeCORS || newRequest.fetchRequestMode() == WebURLRequest::FetchRequestModeCORSWithForcedPreflight) { m_fallbackRequestForServiceWorker = ResourceRequest(request); // m_fallbackRequestForServiceWorker is used when a regular controlling // service worker doesn't handle a cross origin request. When this happens // we still want to give foreign fetch a chance to handle the request, so // only skip the controlling service worker for the fallback request. This // is currently safe because of http://crbug.com/604084 the // wasFallbackRequiredByServiceWorker flag is never set when foreign fetch // handled a request. m_fallbackRequestForServiceWorker.setSkipServiceWorker( WebURLRequest::SkipServiceWorker::Controlling); } loadRequest(newRequest, m_resourceLoaderOptions); return; } dispatchInitialRequest(newRequest); }