Changeset 218149 in webkit


Ignore:
Timestamp:
Jun 12, 2017 3:48:11 PM (7 years ago)
Author:
Simon Fraser
Message:

[iOS WK2] Peeking on an image could result in a preview at the wrong size
https://bugs.webkit.org/show_bug.cgi?id=173274
rdar://problem/30404627

Reviewed by Tim Horton.

There were a couple of issues with the way the page scale is communicated between the web process
and the UI process.

Generally, the page scale is computed by the web process, and sent to the UI process via
layer tree commits. UI-side scale is them communicated back to the web process via visibleContentRect
updates. When receiving a new scale, WebPage has a "scale was set by the UI process" flag to handle
the case where user interaction overrides the viewport-computed page scale. However, this flag would
get set erroneously in a couple of situations.

First, during page loading, layer flushing is suspended temporarily, so web process scale changes never
make it to the UI process. In that scenario, the UI process could send an old scale back to the web process,
setting the "scale was set by the UI process" when it really wasn't.

Secondly, web -> UI layer commit messages, and UI -> web updateVisibleContentRect messages can be in flight at the
same time, again causing a stale scale to reach the web process.

Fix this by only setting the "scale was set by the UI process" when we know the UI scale should be in sync, by comparing
commit IDs of sent and received scales.

  • WebProcess/WebPage/WebPage.h:
  • WebProcess/WebPage/ios/WebPageIOS.mm:

(WebKit::WebPage::scaleFromUIProcess):
(WebKit::WebPage::updateVisibleContentRects):

  • WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.h:

(WebKit::RemoteLayerTreeDrawingArea::lastCommittedTransactionID):

Location:
trunk/Source/WebKit2
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit2/ChangeLog

    r218146 r218149  
     12017-06-12  Simon Fraser  <simon.fraser@apple.com>
     2
     3        [iOS WK2] Peeking on an image could result in a preview at the wrong size
     4        https://bugs.webkit.org/show_bug.cgi?id=173274
     5        rdar://problem/30404627
     6
     7        Reviewed by Tim Horton.
     8
     9        There were a couple of issues with the way the page scale is communicated between the web process
     10        and the UI process.
     11
     12        Generally, the page scale is computed by the web process, and sent to the UI process via
     13        layer tree commits. UI-side scale is them communicated back to the web process via visibleContentRect
     14        updates. When receiving a new scale, WebPage has a "scale was set by the UI process" flag to handle
     15        the case where user interaction overrides the viewport-computed page scale. However, this flag would
     16        get set erroneously in a couple of situations.
     17
     18        First, during page loading, layer flushing is suspended temporarily, so web process scale changes never
     19        make it to the UI process. In that scenario, the UI process could send an old scale back to the web process,
     20        setting the "scale was set by the UI process" when it really wasn't.
     21
     22        Secondly, web -> UI layer commit messages, and UI -> web updateVisibleContentRect messages can be in flight at the
     23        same time, again causing a stale scale to reach the web process.
     24
     25        Fix this by only setting the "scale was set by the UI process" when we know the UI scale should be in sync, by comparing
     26        commit IDs of sent and received scales.
     27
     28        * WebProcess/WebPage/WebPage.h:
     29        * WebProcess/WebPage/ios/WebPageIOS.mm:
     30        (WebKit::WebPage::scaleFromUIProcess):
     31        (WebKit::WebPage::updateVisibleContentRects):
     32        * WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.h:
     33        (WebKit::RemoteLayerTreeDrawingArea::lastCommittedTransactionID):
     34
    1352017-06-12  Alex Christensen  <achristensen@webkit.org>
    236
  • trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h

    r218146 r218149  
    826826    void dynamicViewportSizeUpdate(const WebCore::FloatSize& minimumLayoutSize, const WebCore::FloatSize& maximumUnobscuredSize, const WebCore::FloatRect& targetExposedContentRect, const WebCore::FloatRect& targetUnobscuredRect, const WebCore::FloatRect& targetUnobscuredRectInScrollViewCoordinates, double scale, int32_t deviceOrientation, uint64_t dynamicViewportSizeUpdateID);
    827827    void synchronizeDynamicViewportUpdate(double& newTargetScale, WebCore::FloatPoint& newScrollPosition, uint64_t& nextValidLayerTreeTransactionID);
     828    std::optional<float> scaleFromUIProcess(const VisibleContentRectUpdateInfo&) const;
    828829    void updateVisibleContentRects(const VisibleContentRectUpdateInfo&, MonotonicTime oldestTimestamp);
    829830    bool scaleWasSetByUIProcess() const { return m_scaleWasSetByUIProcess; }
  • trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm

    r217870 r218149  
    31643164}
    31653165
     3166std::optional<float> WebPage::scaleFromUIProcess(const VisibleContentRectUpdateInfo& visibleContentRectUpdateInfo) const
     3167{
     3168    auto transactionIDForLastScaleSentToUIProcess = downcast<RemoteLayerTreeDrawingArea>(*m_drawingArea).lastCommittedTransactionID();
     3169    auto transactionIDForLastScaleFromUIProcess = visibleContentRectUpdateInfo.lastLayerTreeTransactionID();
     3170    if (transactionIDForLastScaleSentToUIProcess != transactionIDForLastScaleFromUIProcess)
     3171        return std::nullopt;
     3172
     3173    float scaleFromUIProcess = visibleContentRectUpdateInfo.scale();
     3174    float currentScale = m_page->pageScaleFactor();
     3175
     3176    double scaleNoiseThreshold = 0.005;
     3177    if (!m_isInStableState && fabs(scaleFromUIProcess - currentScale) < scaleNoiseThreshold) {
     3178        // Tiny changes of scale during interactive zoom cause content to jump by one pixel, creating
     3179        // visual noise. We filter those useless updates.
     3180        scaleFromUIProcess = currentScale;
     3181    }
     3182   
     3183    scaleFromUIProcess = std::min<float>(m_viewportConfiguration.maximumScale(), std::max<float>(m_viewportConfiguration.minimumScale(), scaleFromUIProcess));
     3184    if (areEssentiallyEqualAsFloat(currentScale, scaleFromUIProcess))
     3185        return std::nullopt;
     3186
     3187    return scaleFromUIProcess;
     3188}
     3189
    31663190void WebPage::updateVisibleContentRects(const VisibleContentRectUpdateInfo& visibleContentRectUpdateInfo, MonotonicTime oldestTimestamp)
    31673191{
     
    31753199    m_isInStableState = visibleContentRectUpdateInfo.inStableState();
    31763200
    3177     double scaleNoiseThreshold = 0.005;
    3178     float filteredScale = visibleContentRectUpdateInfo.scale();
    3179     float currentScale = m_page->pageScaleFactor();
    3180 
    3181     if (!m_isInStableState && fabs(filteredScale - currentScale) < scaleNoiseThreshold) {
    3182         // Tiny changes of scale during interactive zoom cause content to jump by one pixel, creating
    3183         // visual noise. We filter those useless updates.
    3184         filteredScale = currentScale;
    3185     }
    3186 
    3187     float boundedScale = std::min<float>(m_viewportConfiguration.maximumScale(), std::max<float>(m_viewportConfiguration.minimumScale(), filteredScale));
     3201    auto scaleFromUIProcess = this->scaleFromUIProcess(visibleContentRectUpdateInfo);
    31883202
    31893203    // Skip progressively redrawing tiles if pinch-zooming while the system is under memory pressure.
    3190     if (boundedScale != currentScale && !m_isInStableState && MemoryPressureHandler::singleton().isUnderMemoryPressure())
     3204    if (scaleFromUIProcess && !m_isInStableState && MemoryPressureHandler::singleton().isUnderMemoryPressure())
    31913205        return;
    31923206
     
    31983212    }
    31993213
     3214    float scaleToUse = scaleFromUIProcess.value_or(m_page->pageScaleFactor());
    32003215    FloatRect exposedContentRect = visibleContentRectUpdateInfo.exposedContentRect();
    3201     FloatRect adjustedExposedContentRect = adjustExposedRectForBoundedScale(exposedContentRect, visibleContentRectUpdateInfo.scale(), boundedScale);
     3216    FloatRect adjustedExposedContentRect = adjustExposedRectForBoundedScale(exposedContentRect, visibleContentRectUpdateInfo.scale(), scaleToUse);
    32023217    m_drawingArea->setExposedContentRect(adjustedExposedContentRect);
    32033218
     
    32053220
    32063221    bool hasSetPageScale = false;
    3207     if (boundedScale != currentScale) {
     3222    if (scaleFromUIProcess) {
    32083223        m_scaleWasSetByUIProcess = true;
    32093224        m_hasStablePageScaleFactor = m_isInStableState;
     
    32113226        m_dynamicSizeUpdateHistory.clear();
    32123227
    3213         m_page->setPageScaleFactor(boundedScale, scrollPosition, m_isInStableState);
     3228        m_page->setPageScaleFactor(scaleFromUIProcess.value(), scrollPosition, m_isInStableState);
    32143229        hasSetPageScale = true;
    3215         send(Messages::WebPageProxy::PageScaleFactorDidChange(boundedScale));
    3216     }
    3217 
     3230        send(Messages::WebPageProxy::PageScaleFactorDidChange(scaleFromUIProcess.value()));
     3231    }
     3232   
    32183233    if (!hasSetPageScale && m_isInStableState) {
    3219         m_page->setPageScaleFactor(boundedScale, scrollPosition, true);
     3234        m_page->setPageScaleFactor(scaleToUse, scrollPosition, true);
    32203235        hasSetPageScale = true;
    32213236    }
  • trunk/Source/WebKit2/WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.h

    r217475 r218149  
    5252
    5353    uint64_t nextTransactionID() const { return m_currentTransactionID + 1; }
     54    uint64_t lastCommittedTransactionID() const { return m_currentTransactionID; }
    5455
    5556    WeakPtr<RemoteLayerTreeDrawingArea> createWeakPtr() { return m_weakPtrFactory.createWeakPtr(); }
    56    
     57
    5758private:
    5859    // DrawingArea
     
    146147
    147148    WebCore::Timer m_layerFlushTimer;
    148     bool m_isFlushingSuspended;
    149     bool m_hasDeferredFlush;
    150     bool m_isThrottlingLayerFlushes;
    151     bool m_isLayerFlushThrottlingTemporarilyDisabledForInteraction;
    152     bool m_isInitialThrottledLayerFlush;
     149    bool m_isFlushingSuspended { false };
     150    bool m_hasDeferredFlush { false };
     151    bool m_isThrottlingLayerFlushes { false };
     152    bool m_isLayerFlushThrottlingTemporarilyDisabledForInteraction { false };
     153    bool m_isInitialThrottledLayerFlush { false };
    153154
    154     bool m_waitingForBackingStoreSwap;
    155     bool m_hadFlushDeferredWhileWaitingForBackingStoreSwap;
     155    bool m_waitingForBackingStoreSwap { false };
     156    bool m_hadFlushDeferredWhileWaitingForBackingStoreSwap { false };
    156157    bool m_nextFlushIsForImmediatePaint { false };
    157158
     
    160161
    161162    HashSet<RemoteLayerTreeDisplayRefreshMonitor*> m_displayRefreshMonitors;
    162     HashSet<RemoteLayerTreeDisplayRefreshMonitor*>* m_displayRefreshMonitorsToNotify;
     163    HashSet<RemoteLayerTreeDisplayRefreshMonitor*>* m_displayRefreshMonitorsToNotify { nullptr };
    163164
    164     uint64_t m_currentTransactionID;
     165    uint64_t m_currentTransactionID { 0 };
    165166    Vector<RemoteLayerTreeTransaction::TransactionCallbackID> m_pendingCallbackIDs;
    166167
    167168    WebCore::LayoutMilestones m_pendingNewlyReachedLayoutMilestones { 0 };
    168169
    169     WebCore::GraphicsLayer* m_contentLayer;
    170     WebCore::GraphicsLayer* m_viewOverlayRootLayer;
     170    WebCore::GraphicsLayer* m_contentLayer { nullptr };
     171    WebCore::GraphicsLayer* m_viewOverlayRootLayer { nullptr };
    171172   
    172173    WeakPtrFactory<RemoteLayerTreeDrawingArea> m_weakPtrFactory;
  • trunk/Source/WebKit2/WebProcess/WebPage/mac/RemoteLayerTreeDrawingArea.mm

    r217475 r218149  
    6161    , m_rootLayer(GraphicsLayer::create(graphicsLayerFactory(), *this))
    6262    , m_layerFlushTimer(*this, &RemoteLayerTreeDrawingArea::flushLayers)
    63     , m_isFlushingSuspended(false)
    64     , m_hasDeferredFlush(false)
    65     , m_isThrottlingLayerFlushes(false)
    66     , m_isLayerFlushThrottlingTemporarilyDisabledForInteraction(false)
    67     , m_isInitialThrottledLayerFlush(false)
    68     , m_waitingForBackingStoreSwap(false)
    69     , m_hadFlushDeferredWhileWaitingForBackingStoreSwap(false)
    70     , m_displayRefreshMonitorsToNotify(nullptr)
    71     , m_currentTransactionID(0)
    72     , m_contentLayer(nullptr)
    73     , m_viewOverlayRootLayer(nullptr)
    7463    , m_weakPtrFactory(this)
    7564{
Note: See TracChangeset for help on using the changeset viewer.