Changeset 261985 in webkit
- Timestamp:
- May 20, 2020, 11:47:24 PM (6 years ago)
- Location:
- trunk
- Files:
-
- 18 edited
-
Source/WTF/ChangeLog (modified) (1 diff)
-
Source/WTF/wtf/SystemTracing.h (modified) (1 diff)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/page/Page.cpp (modified) (2 diffs)
-
Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp (modified) (1 diff)
-
Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h (modified) (2 diffs)
-
Source/WebCore/page/scrolling/ScrollingCoordinator.h (modified) (1 diff)
-
Source/WebCore/page/scrolling/ScrollingTree.cpp (modified) (7 diffs)
-
Source/WebCore/page/scrolling/ScrollingTree.h (modified) (3 diffs)
-
Source/WebCore/page/scrolling/ScrollingTreeNode.h (modified) (1 diff)
-
Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp (modified) (2 diffs)
-
Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h (modified) (3 diffs)
-
Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp (modified) (3 diffs)
-
Source/WebCore/page/scrolling/ThreadedScrollingTree.h (modified) (2 diffs)
-
Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.h (modified) (1 diff)
-
Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm (modified) (1 diff)
-
Tools/ChangeLog (modified) (1 diff)
-
Tools/Tracing/SystemTracePoints.plist (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WTF/ChangeLog
r261978 r261985 1 2020-05-20 Simon Fraser <simon.fraser@apple.com> 2 3 [macOS] Scrolling synchronization part 1: Have the scrolling thread wait half a frame for the main thread to complete the rendering update 4 https://bugs.webkit.org/show_bug.cgi?id=212168 5 6 Reviewed by Tim Horton. 7 8 Some new trace points for scrolling thread activity. 9 10 * wtf/SystemTracing.h: 11 1 12 2020-05-20 Tim Horton <timothy_horton@apple.com> 2 13 -
trunk/Source/WTF/wtf/SystemTracing.h
r257898 r261985 91 91 DisplayListReplayStart, 92 92 DisplayListReplayEnd, 93 ScrollingThreadRenderUpdateSyncStart, 94 ScrollingThreadRenderUpdateSyncEnd, 95 ScrollingThreadDisplayDidRefreshStart, 96 ScrollingThreadDisplayDidRefreshEnd, 93 97 94 98 WebKitRange = 10000, -
trunk/Source/WebCore/ChangeLog
r261984 r261985 1 2020-05-20 Simon Fraser <simon.fraser@apple.com> 2 3 [macOS] Scrolling synchronization part 1: Have the scrolling thread wait half a frame for the main thread to complete the rendering update 4 https://bugs.webkit.org/show_bug.cgi?id=212168 5 6 Reviewed by Tim Horton. 7 8 Currently the scrolling thread is a free-running thread that moves layers around in response 9 to wheel events, and asynchronously posts data about scrolled layers back to the main thread. 10 That results in an almost guaranteed lack of synchronization between the displayed layer 11 positions, and the web-exposed values for scroll position (element.scrollTop, window.pageYOffset etc). 12 This is a frequent source of stuttering or jumpy web content when scrolling. 13 14 The first step to fixing this is to synchronize the scrolling thread layer positions 15 and the main thread state for the case where the main thread is responsive enough to 16 render once per frame. This is achieved as follow: 17 - When the main thread is starting a rendering update, Page::updateRendering() informs 18 the scrolling tree via ScrollingCoordinatorMac::willStartRenderingUpdate(). This 19 atomically waits for the scrolling thread to take the m_treeMutex (via a BinarySemaphore) 20 and starts waiting on the m_stateCondition Condition. Now the main thread pulls the 21 state of the scrolling tree via synchronizeStateFromScrollingTree() and uses it for 22 the rendering update. 23 - If the rendering update finishes within half a frame (8ms), then m_stateCondition 24 is released, and the scrolling thread assumes that the main thread is going to 25 commit layers rapidly enough to preserve 60fps scrolling. 26 - If the rendering update takes too long, m_stateCondition times out, and the scrolling 27 thread applies layer positions, triggering a CA commit on that thread. 28 29 We no longer apply layer positions directly when handling wheel events. 30 31 synchronizeStateFromScrollingTree() has to only pull state from nodes that have moved on the scrolling thread, 32 so track that via ScrollingTreeScrollingNode::scrolledSinceLastCommit() and adjust the visitor function to 33 make it available during scrolling tree traversal. 34 35 * page/Page.cpp: 36 (WebCore::Page::updateRendering): 37 (WebCore::Page::finalizeRenderingUpdate): 38 * page/scrolling/AsyncScrollingCoordinator.cpp: 39 (WebCore::AsyncScrollingCoordinator::synchronizeStateFromScrollingTree): 40 * page/scrolling/AsyncScrollingCoordinator.h: 41 * page/scrolling/ScrollingCoordinator.h: 42 (WebCore::ScrollingCoordinator::willStartRenderingUpdate): 43 (WebCore::ScrollingCoordinator::didCompleteRenderingUpdate): 44 (WebCore::ScrollingCoordinator::synchronizeStateFromScrollingTree): Deleted. 45 * page/scrolling/ScrollingTree.cpp: 46 (WebCore::ScrollingTree::handleWheelEvent): 47 (WebCore::ScrollingTree::traverseScrollingTreeRecursive): 48 (WebCore::ScrollingTree::commitTreeState): 49 (WebCore::ScrollingTree::updateTreeFromStateNodeRecursive): 50 (WebCore::ScrollingTree::applyLayerPositionsInternal): 51 (WebCore::ScrollingTree::nominalFramesPerSecond): 52 * page/scrolling/ScrollingTree.h: 53 * page/scrolling/ScrollingTreeNode.h: 54 (WebCore::ScrollingTreeNode::didCompleteCommitForNode): 55 * page/scrolling/ScrollingTreeScrollingNode.cpp: 56 (WebCore::ScrollingTreeScrollingNode::didCompleteCommitForNode): 57 (WebCore::ScrollingTreeScrollingNode::currentScrollPositionChanged): 58 * page/scrolling/ScrollingTreeScrollingNode.h: 59 * page/scrolling/ThreadedScrollingTree.cpp: 60 (WebCore::ThreadedScrollingTree::willStartRenderingUpdate): 61 (WebCore::ThreadedScrollingTree::maxAllowableRenderingUpdateDurationForSynchronization): 62 (WebCore::ThreadedScrollingTree::waitForRenderingUpdateCompletionOrTimeout): 63 (WebCore::ThreadedScrollingTree::didCompleteRenderingUpdate): 64 (WebCore::ThreadedScrollingTree::displayDidRefreshOnScrollingThread): 65 * page/scrolling/ThreadedScrollingTree.h: 66 (WebCore::ThreadedScrollingTree::treeMutex): 67 * page/scrolling/mac/ScrollingCoordinatorMac.h: 68 * page/scrolling/mac/ScrollingCoordinatorMac.mm: 69 (WebCore::ScrollingCoordinatorMac::willStartRenderingUpdate): 70 (WebCore::ScrollingCoordinatorMac::didCompleteRenderingUpdate): 71 1 72 2020-05-20 Chris Fleizach <cfleizach@apple.com> 2 73 -
trunk/Source/WebCore/page/Page.cpp
r261948 r261985 1361 1361 layoutIfNeeded(); 1362 1362 1363 #if ENABLE(ASYNC_SCROLLING) 1364 if (auto* scrollingCoordinator = this->scrollingCoordinator()) 1365 scrollingCoordinator->willStartRenderingUpdate(); 1366 #endif 1367 1363 1368 // Timestamps should not change while serving the rendering update steps. 1364 1369 Vector<WeakPtr<Document>> initialDocuments; … … 1479 1484 if (flags.contains(FinalizeRenderingUpdateFlags::ApplyScrollingTreeLayerPositions)) 1480 1485 scrollingCoordinator->applyScrollingTreeLayerPositions(); 1486 1487 scrollingCoordinator->didCompleteRenderingUpdate(); 1481 1488 } 1482 1489 #endif -
trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp
r261948 r261985 297 297 ASSERT(isMainThread()); 298 298 299 m_scrollingTree->traverseScrollingTree([&](ScrollingNodeID nodeID, ScrollingNodeType, Optional<FloatPoint> scrollPosition, Optional<FloatPoint> layoutViewportOrigin ) {300 if (scrollPosition ) {299 m_scrollingTree->traverseScrollingTree([&](ScrollingNodeID nodeID, ScrollingNodeType, Optional<FloatPoint> scrollPosition, Optional<FloatPoint> layoutViewportOrigin, bool scrolledSinceLastCommit) { 300 if (scrollPosition && scrolledSinceLastCommit) { 301 301 LOG_WITH_STREAM(Scrolling, stream << "AsyncScrollingCoordinator::synchronizeStateFromScrollingTree - node " << nodeID << " scroll position " << scrollPosition); 302 302 updateScrollPositionAfterAsyncScroll(nodeID, scrollPosition.value(), layoutViewportOrigin, ScrollType::User, ScrollingLayerPositionAction::Set); -
trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h
r261948 r261985 83 83 WEBCORE_EXPORT String scrollingTreeAsText(ScrollingStateTreeAsTextBehavior = ScrollingStateTreeAsTextBehaviorNormal) const override; 84 84 WEBCORE_EXPORT void willCommitTree() override; 85 void synchronizeStateFromScrollingTree(); 85 86 86 87 bool eventTrackingRegionsDirty() const { return m_eventTrackingRegionsDirty; } … … 103 104 104 105 WEBCORE_EXPORT void applyScrollingTreeLayerPositions() override; 105 WEBCORE_EXPORT void synchronizeStateFromScrollingTree() override;106 106 107 107 WEBCORE_EXPORT ScrollingNodeID createNode(ScrollingNodeType, ScrollingNodeID newNodeID) override; -
trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h
r261948 r261985 114 114 virtual void applyScrollingTreeLayerPositions() { } 115 115 116 // Takes scroll positions from the scrolling tree and applies them to ScrollableAreas.117 virtual void synchronizeStateFromScrollingTree() { }116 virtual void willStartRenderingUpdate() { } 117 virtual void didCompleteRenderingUpdate() { } 118 118 119 119 #if ENABLE(KINETIC_SCROLLING) -
trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp
r261948 r261985 159 159 }(); 160 160 161 if (result == ScrollingEventResult::DidHandleEvent)162 applyLayerPositionsInternal();163 164 161 return result; 165 162 } … … 188 185 void ScrollingTree::traverseScrollingTreeRecursive(ScrollingTreeNode& node, const VisitorFunction& visitorFunction) 189 186 { 187 bool scrolledSinceLastCommit = false; 190 188 Optional<FloatPoint> scrollPosition; 191 if (is<ScrollingTreeScrollingNode>(node)) 192 scrollPosition = downcast<ScrollingTreeScrollingNode>(node).currentScrollPosition(); 189 if (is<ScrollingTreeScrollingNode>(node)) { 190 auto& scrollingNode = downcast<ScrollingTreeScrollingNode>(node); 191 scrollPosition = scrollingNode.currentScrollPosition(); 192 scrolledSinceLastCommit = scrollingNode.scrolledSinceLastCommit(); 193 } 193 194 194 195 Optional<FloatPoint> layoutViewportOrigin; … … 196 197 layoutViewportOrigin = downcast<ScrollingTreeFrameScrollingNode>(node).layoutViewport().location(); 197 198 198 visitorFunction(node.scrollingNodeID(), node.nodeType(), scrollPosition, layoutViewportOrigin );199 visitorFunction(node.scrollingNodeID(), node.nodeType(), scrollPosition, layoutViewportOrigin, scrolledSinceLastCommit); 199 200 200 201 for (auto& child : node.children()) … … 218 219 219 220 bool rootStateNodeChanged = scrollingStateTree->hasNewRootStateNode(); 220 221 221 222 LOG(ScrollingTree, "\nScrollingTree %p commitTreeState", this); 222 223 223 224 auto* rootNode = scrollingStateTree->rootStateNode(); 224 225 if (rootNode … … 328 329 329 330 node->commitStateAfterChildren(*stateNode); 330 331 node->didCompleteCommitForNode(); 332 331 333 #if ENABLE(SCROLLING_THREAD) 332 334 if (is<ScrollingTreeScrollingNode>(*node) && !downcast<ScrollingTreeScrollingNode>(*node).synchronousScrollingReasons().isEmpty()) … … 355 357 void ScrollingTree::applyLayerPositionsInternal() 356 358 { 359 ASSERT(m_treeMutex.isLocked()); 357 360 if (!m_rootNode) 358 361 return; … … 539 542 LockHolder locker(m_treeStateMutex); 540 543 return m_treeState.displayID; 544 } 545 546 Optional<unsigned> ScrollingTree::nominalFramesPerSecond() 547 { 548 LockHolder locker(m_treeStateMutex); 549 return m_treeState.nominalFramesPerSecond; 541 550 } 542 551 -
trunk/Source/WebCore/page/scrolling/ScrollingTree.h
r261948 r261985 91 91 WEBCORE_EXPORT ScrollingTreeNode* nodeForID(ScrollingNodeID) const; 92 92 93 using VisitorFunction = WTF::Function<void (ScrollingNodeID, ScrollingNodeType, Optional<FloatPoint> scrollPosition, Optional<FloatPoint> layoutViewportOrigin )>;93 using VisitorFunction = WTF::Function<void (ScrollingNodeID, ScrollingNodeType, Optional<FloatPoint> scrollPosition, Optional<FloatPoint> layoutViewportOrigin, bool scrolledSinceLastCommit)>; 94 94 void traverseScrollingTree(VisitorFunction&&); 95 95 … … 189 189 WEBCORE_EXPORT virtual ScrollingEventResult handleWheelEvent(const PlatformWheelEvent&); 190 190 191 Optional<unsigned> nominalFramesPerSecond(); 192 193 void applyLayerPositionsInternal(); 194 Lock m_treeMutex; // Protects the scrolling tree. 195 191 196 private: 192 197 void updateTreeFromStateNodeRecursive(const ScrollingStateNode*, struct CommitTreeState&); 193 198 virtual void propagateSynchronousScrollingReasons(const HashSet<ScrollingNodeID>&) { } 194 199 195 void applyLayerPositionsInternal();196 197 200 void applyLayerPositionsRecursive(ScrollingTreeNode&); 198 201 void notifyRelatedNodesRecursive(ScrollingTreeNode&); … … 202 205 WEBCORE_EXPORT virtual OptionSet<EventListenerRegionType> eventListenerRegionTypesForPoint(FloatPoint) const; 203 206 virtual void receivedWheelEvent(const PlatformWheelEvent&) { } 204 205 Lock m_treeMutex; // Protects the scrolling tree.206 207 207 208 RefPtr<ScrollingTreeFrameScrollingNode> m_rootNode; -
trunk/Source/WebCore/page/scrolling/ScrollingTreeNode.h
r257268 r261985 61 61 virtual void commitStateBeforeChildren(const ScrollingStateNode&) = 0; 62 62 virtual void commitStateAfterChildren(const ScrollingStateNode&) { } 63 virtual void didCompleteCommitForNode() { } 63 64 64 65 ScrollingTreeNode* parent() const { return m_parent; } -
trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp
r261849 r261985 125 125 } 126 126 127 void ScrollingTreeScrollingNode::didCompleteCommitForNode() 128 { 129 m_scrolledSinceLastCommit = false; 130 } 131 127 132 bool ScrollingTreeScrollingNode::isLatchedNode() const 128 133 { … … 251 256 { 252 257 scrollingTree().scrollingTreeNodeDidScroll(*this); 258 m_scrolledSinceLastCommit = true; 253 259 } 254 260 -
trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h
r261132 r261985 53 53 void commitStateBeforeChildren(const ScrollingStateNode&) override; 54 54 void commitStateAfterChildren(const ScrollingStateNode&) override; 55 void didCompleteCommitForNode() final; 55 56 56 57 virtual bool canHandleWheelEvent(const PlatformWheelEvent&) const; … … 104 105 105 106 bool eventCanScrollContents(const PlatformWheelEvent&) const; 107 108 bool scrolledSinceLastCommit() const { return m_scrolledSinceLastCommit; } 106 109 107 110 const LayerRepresentation& scrollContainerLayer() const { return m_scrollContainerLayer; } … … 163 166 #endif 164 167 bool m_isFirstCommit { true }; 168 bool m_scrolledSinceLastCommit { false }; 165 169 166 170 LayerRepresentation m_scrollContainerLayer; -
trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp
r261876 r261985 39 39 #include <wtf/RunLoop.h> 40 40 #include <wtf/SetForScope.h> 41 #include <wtf/SystemTracing.h> 41 42 #include <wtf/text/TextStream.h> 43 #include <wtf/threads/BinarySemaphore.h> 42 44 43 45 namespace WebCore { … … 203 205 #endif 204 206 207 void ThreadedScrollingTree::willStartRenderingUpdate() 208 { 209 ASSERT(isMainThread()); 210 211 tracePoint(ScrollingThreadRenderUpdateSyncStart); 212 213 // Wait for the scrolling thread to acquire m_treeMutex. This ensures that any pending wheel events are processed. 214 BinarySemaphore semaphore; 215 ScrollingThread::dispatch([protectedThis = makeRef(*this), &semaphore]() { 216 LockHolder treeLocker(protectedThis->m_treeMutex); 217 semaphore.signal(); 218 protectedThis->waitForRenderingUpdateCompletionOrTimeout(); 219 }); 220 semaphore.wait(); 221 m_state = SynchronizationState::InRenderingUpdate; 222 } 223 224 Seconds ThreadedScrollingTree::maxAllowableRenderingUpdateDurationForSynchronization() 225 { 226 constexpr double allowableFrameFraction = 0.5; 227 auto displayFPS = nominalFramesPerSecond().valueOr(60); 228 Seconds frameDuration = 1_s / (double)displayFPS; 229 return allowableFrameFraction * frameDuration; 230 } 231 232 // This code allows the main thread about half a frame to complete its rendering udpate. If the main thread 233 // is responsive (i.e. managing to render every frame), then we expect to get a didCompleteRenderingUpdate() 234 // within 8ms of willStartRenderingUpdate(). We time this via m_stateCondition, which blocks the scrolling 235 // thread (with m_treeMutex locked at the start and end) so that we don't handle wheel events while waiting. 236 // If the condition times out, we know the main thread is being slow, and allow the scrolling thread to 237 // commit layer positions. 238 void ThreadedScrollingTree::waitForRenderingUpdateCompletionOrTimeout() 239 { 240 ASSERT(ScrollingThread::isCurrentThread()); 241 ASSERT(m_treeMutex.isLocked()); 242 243 auto startTime = MonotonicTime::now(); 244 auto timeoutTime = startTime + maxAllowableRenderingUpdateDurationForSynchronization(); 245 246 bool becameIdle = m_stateCondition.waitUntil(m_treeMutex, timeoutTime, [&] { 247 return m_state == SynchronizationState::Idle; 248 }); 249 250 ASSERT(m_treeMutex.isLocked()); 251 252 if (!becameIdle) { 253 m_state = SynchronizationState::Desynchronized; 254 // At this point we know the main thread is taking too long in the rendering update, 255 // so we give up trying to sync with the main thread and update layers here on the scrolling thread. 256 applyLayerPositionsInternal(); 257 tracePoint(ScrollingThreadRenderUpdateSyncEnd, 1); 258 } else 259 tracePoint(ScrollingThreadRenderUpdateSyncEnd); 260 } 261 262 void ThreadedScrollingTree::didCompleteRenderingUpdate() 263 { 264 ASSERT(isMainThread()); 265 LockHolder treeLocker(m_treeMutex); 266 267 if (m_state == SynchronizationState::InRenderingUpdate) 268 m_stateCondition.notifyOne(); 269 270 m_state = SynchronizationState::Idle; 271 } 272 273 void ThreadedScrollingTree::displayDidRefreshOnScrollingThread() 274 { 275 TraceScope tracingScope(ScrollingThreadDisplayDidRefreshStart, ScrollingThreadDisplayDidRefreshEnd); 276 ASSERT(ScrollingThread::isCurrentThread()); 277 278 LockHolder treeLocker(m_treeMutex); 279 280 if (m_state != SynchronizationState::Idle) 281 applyLayerPositionsInternal(); 282 283 switch (m_state) { 284 case SynchronizationState::Idle: { 285 m_state = SynchronizationState::WaitingForRenderingUpdate; 286 break; 287 } 288 case SynchronizationState::WaitingForRenderingUpdate: 289 case SynchronizationState::InRenderingUpdate: 290 case SynchronizationState::Desynchronized: 291 break; 292 } 293 } 294 205 295 void ThreadedScrollingTree::displayDidRefresh(PlatformDisplayID displayID) 206 296 { … … 217 307 } 218 308 219 void ThreadedScrollingTree::displayDidRefreshOnScrollingThread()220 {221 ASSERT(ScrollingThread::isCurrentThread());222 }223 224 309 } // namespace WebCore 225 310 -
trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.h
r261876 r261985 58 58 WEBCORE_EXPORT void displayDidRefresh(PlatformDisplayID); 59 59 60 void willStartRenderingUpdate(); 61 void didCompleteRenderingUpdate(); 62 63 Lock& treeMutex() { return m_treeMutex; } 64 60 65 protected: 61 66 explicit ThreadedScrollingTree(AsyncScrollingCoordinator&); … … 80 85 81 86 void displayDidRefreshOnScrollingThread(); 87 void waitForRenderingUpdateCompletionOrTimeout(); 88 89 Seconds maxAllowableRenderingUpdateDurationForSynchronization(); 82 90 83 91 RefPtr<AsyncScrollingCoordinator> m_scrollingCoordinator; 92 93 enum class SynchronizationState : uint8_t { 94 Idle, 95 WaitingForRenderingUpdate, 96 InRenderingUpdate, 97 Desynchronized, 98 }; 99 100 SynchronizationState m_state { SynchronizationState::Idle }; 101 Condition m_stateCondition; 84 102 }; 85 103 -
trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.h
r261539 r261985 47 47 void scheduleTreeStateCommit() final; 48 48 49 void willStartRenderingUpdate() final; 50 void didCompleteRenderingUpdate() final; 51 49 52 void updateTiledScrollingIndicator(); 50 53 -
trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm
r261849 r261985 111 111 } 112 112 113 void ScrollingCoordinatorMac::willStartRenderingUpdate() 114 { 115 RefPtr<ThreadedScrollingTree> threadedScrollingTree = downcast<ThreadedScrollingTree>(scrollingTree()); 116 threadedScrollingTree->willStartRenderingUpdate(); 117 synchronizeStateFromScrollingTree(); 118 } 119 120 void ScrollingCoordinatorMac::didCompleteRenderingUpdate() 121 { 122 downcast<ThreadedScrollingTree>(scrollingTree())->didCompleteRenderingUpdate(); 123 } 124 113 125 void ScrollingCoordinatorMac::updateTiledScrollingIndicator() 114 126 { -
trunk/Tools/ChangeLog
r261972 r261985 1 2020-05-20 Simon Fraser <simon.fraser@apple.com> 2 3 [macOS] Scrolling synchronization part 1: Have the scrolling thread wait half a frame for the main thread to complete the rendering update 4 https://bugs.webkit.org/show_bug.cgi?id=212168 5 6 Reviewed by Tim Horton. 7 8 Some new trace points for scrolling thread activity. 9 10 * Tracing/SystemTracePoints.plist: 11 1 12 2020-05-20 Wenson Hsieh <wenson_hsieh@apple.com> 2 13 -
trunk/Tools/Tracing/SystemTracePoints.plist
r257898 r261985 340 340 <dict> 341 341 <key>Name</key> 342 <string>Scrolling Sync</string> 343 <key>Type</key> 344 <string>Interval</string> 345 <key>Component</key> 346 <string>47</string> 347 <key>CodeBegin</key> 348 <string>5040</string> 349 <key>CodeEnd</key> 350 <string>5041</string> 351 </dict> 352 <dict> 353 <key>Name</key> 354 <string>Scrolling Thread DisplayDidRefresh</string> 355 <key>Type</key> 356 <string>Interval</string> 357 <key>Component</key> 358 <string>47</string> 359 <key>CodeBegin</key> 360 <string>5042</string> 361 <key>CodeEnd</key> 362 <string>5043</string> 363 </dict> 364 <dict> 365 <key>Name</key> 342 366 <string>Paint WebHTMLView</string> 343 367 <key>Type</key>
Note:
See TracChangeset
for help on using the changeset viewer.