Changeset 75987 in webkit
- Timestamp:
- Jan 17, 2011 5:45:56 PM (13 years ago)
- Location:
- trunk/Source
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r75986 r75987 1 2011-01-17 Adam Roben <aroben@apple.com> 2 3 Remove special-cased support for providing content for the root layer 4 5 Clients will just have to provide content through the normal 6 GraphicsLayer channels now! 7 8 Support for <http://webkit.org/b/52582> WebView should paint directly 9 into a GraphicsLayer when in accelerated compositing mode 10 11 Reviewed by Simon Fraser and Chris Marrin. 12 13 * platform/graphics/win/WKCACFLayerRenderer.cpp: 14 (WebCore::WKCACFLayerRenderer::WKCACFLayerRenderer): Removed 15 initialization of m_backingStoreDirty, which has itself been removed. 16 (WebCore::WKCACFLayerRenderer::setNeedsDisplay): Moved code to schedule 17 a sync from here to syncCompositingStateSoon. We only need to call 18 renderSoon if we don't call syncCompositingStateSoon; the latter 19 function calls the former. 20 (WebCore::WKCACFLayerRenderer::paint): Removed code to handle 21 m_backingStoreDirty. We don't want to know anything about clients' 22 backing stores. 23 (WebCore::WKCACFLayerRenderer::syncCompositingStateSoon): Added. Code 24 came from setNeedsDisplay. 25 26 * platform/graphics/win/WKCACFLayerRenderer.h: 27 Removed setRootContents[AndDisplay], setBackingStoreDirty, and 28 m_backingStoreDirty. Made paint() public so that clients can force a 29 synchronous render (e.g., when handling WM_PAINT). 30 1 31 2011-01-17 Adam Roben <aroben@apple.com> 2 32 -
trunk/Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.cpp
r75986 r75987 188 188 , m_hostWindow(0) 189 189 , m_renderTimer(this, &WKCACFLayerRenderer::renderTimerFired) 190 , m_backingStoreDirty(false)191 190 , m_mustResetLostDeviceBeforeRendering(false) 192 191 , m_syncLayerChanges(false) … … 240 239 } 241 240 242 void WKCACFLayerRenderer::setRootContents(CGImageRef image)243 {244 ASSERT(m_rootLayer);245 m_rootLayer->setContents(image);246 renderSoon();247 }248 249 void WKCACFLayerRenderer::setRootContentsAndDisplay(CGImageRef image)250 {251 ASSERT(m_rootLayer);252 m_rootLayer->setContents(image);253 paint();254 }255 256 241 void WKCACFLayerRenderer::setRootChildLayer(PlatformCALayer* layer) 257 242 { … … 270 255 void WKCACFLayerRenderer::setNeedsDisplay(bool sync) 271 256 { 272 if (!m_syncLayerChanges && sync)273 m_syncLayerChanges = true;274 275 257 ASSERT(m_rootLayer); 276 258 m_rootLayer->setNeedsDisplay(0); 277 renderSoon(); 259 260 if (sync) 261 syncCompositingStateSoon(); 262 else 263 renderSoon(); 278 264 } 279 265 … … 421 407 if (m_mightBeAbleToCreateDeviceLater) 422 408 renderSoon(); 423 return;424 }425 426 if (m_backingStoreDirty) {427 // If the backing store is still dirty when we are about to draw the428 // composited content, we need to force the window to paint into the429 // backing store. The paint will only paint the dirty region that430 // if being tracked in WebView.431 UpdateWindow(m_hostWindow);432 409 return; 433 410 } … … 547 524 } 548 525 526 void WKCACFLayerRenderer::syncCompositingStateSoon() 527 { 528 m_syncLayerChanges = true; 529 renderSoon(); 530 } 531 549 532 CGRect WKCACFLayerRenderer::bounds() const 550 533 { -
trunk/Source/WebCore/platform/graphics/win/WKCACFLayerRenderer.h
r75262 r75987 71 71 static bool acceleratedCompositingAvailable(); 72 72 73 void setRootContents(CGImageRef);74 void setRootContentsAndDisplay(CGImageRef);75 73 void setRootChildLayer(PlatformCALayer*); 76 74 void layerTreeDidChange(); 77 75 void setNeedsDisplay(bool sync = false); 78 76 void setHostWindow(HWND window) { m_hostWindow = window; } 79 void setBackingStoreDirty(bool dirty) { m_backingStoreDirty = dirty; }80 77 bool createRenderer(); 81 78 void destroyRenderer(); 79 void paint(); 82 80 void resize(); 83 81 void renderSoon(); 82 void syncCompositingStateSoon(); 84 83 85 84 protected: … … 103 102 104 103 void render(const Vector<CGRect>& dirtyRects = Vector<CGRect>()); 105 void paint();106 104 107 105 WKCACFLayerRendererClient* m_client; … … 113 111 HWND m_hostWindow; 114 112 Timer<WKCACFLayerRenderer> m_renderTimer; 115 bool m_backingStoreDirty;116 113 bool m_mustResetLostDeviceBeforeRendering; 117 114 bool m_syncLayerChanges; -
trunk/Source/WebKit/win/ChangeLog
r75971 r75987 1 2011-01-17 Adam Roben <aroben@apple.com> 2 3 Paint directly into a GraphicsLayer when using accelerated compositing 4 5 Before this patch, we were painting into our normal backing store 6 HBITMAP, wrapping it in a CGImage, and handing it off to Core 7 Animation. This had at least two disadvantages: 8 1) The bitmap could be modified while Core Animation was using it. 9 2) It introduced extra complexity. 10 11 When entering accelerated compositing mode, WebView now creates a 12 GraphicsLayer to draw into. This GraphicsLayer sits between the root 13 layer (owned by WKCACFLayerRenderer) and the RenderView's layer. When 14 WebView invalidates, it just calls setNeedsDisplayInRect on its 15 GraphicsLayer. When WebView paints, it just tells its 16 WKCACFLayerRenderer to paint, which will call back to WebView to draw 17 into the GraphicsLayer if it has a dirty region. This is very similar 18 to the current implementation of LayerBackedDrawingArea in WebKit2. 19 20 Fixes <http://webkit.org/b/52582> WebView should paint directly into a 21 GraphicsLayer when in accelerated compositing mode 22 23 Reviewed by Simon Fraser and Chris Marrin. 24 25 * WebCoreSupport/WebChromeClient.cpp: 26 (WebChromeClient::attachRootGraphicsLayer): 27 (WebChromeClient::scheduleCompositingLayerSync): 28 Updated for WebView changes. 29 30 * WebView.cpp: 31 (WebView::repaint): When using accelerated compositing, just invalidate 32 our backing layer. This matches the behavior of LayerBackedDrawingArea. 33 (WebView::deleteBackingStore): Removed accelerated compositing code. 34 The WKCACFLayerRenderer doesn't need to know about our backing store 35 anymore; we don't use it at all when in accelerated compositing mode. 36 (WebView::addToDirtyRegion): When using accelerated compositing, just 37 invalidate our backing layer. 38 (WebView::scrollBackingStore): Added an assertion that this isn't 39 called in accelerated compositing mode. 40 (WebView::sizeChanged): Update our backing layer's size, too, and 41 invalidate it. 42 (WebView::updateBackingStore): Added an assertion that this isn't 43 called in accelerated compositing mode. 44 (WebView::paint): If we're in accelerated compositing mode, sync our 45 compositing state. If we're *still* in accelerated compositing mode, 46 just tell our WKCACFLayerRenderer to paint and clear our dirty region. 47 (The later changes in this function are just un-indenting code that 48 used to be inside an if.) 49 50 (WebView::paintIntoBackingStore): 51 (WebView::paintIntoWindow): 52 Added assertions that these aren't called in accelerated compositing 53 mode. 54 55 (WebView::WebViewWndProc): Updated WM_XP_THEMECHANGED handling for 56 removal of setRootLayerNeedsDisplay. 57 (WebView::setRootChildLayer): Changed to take a GraphicsLayer. We now 58 set the layer as a child of our own backing layer. 59 (WebView::scheduleCompositingLayerSync): Just call through to 60 WKCACFLayerRenderer. 61 (WebView::setAcceleratedCompositing): Create our backing layer and set 62 it as the child of WKCACFLayerRenderer's root layer. 63 (WebView::notifyAnimationStarted): Added. We never expect this 64 GraphicsLayerClient override to be called, as we don't use animations 65 on our backing layer. 66 (WebView::notifySyncRequired): Added. Just schedule a sync. 67 (WebView::paintContents): Added. Just clip and paint! 68 69 (WebView::showDebugBorders): 70 (WebView::showRepaintCounter): 71 Added. These just call through to Settings. 72 73 (WebView::syncCompositingState): Changed to first update layout, then 74 sync state for our backing layer, then sync WebCore's state. This 75 matches LayerBackedDrawingArea. 76 77 * WebView.h: WebView now implements the GraphicsLayerClient interface. 78 Removed setRootLayerNeedsDisplay; it's been replaced by calling 79 setNeedsDisplay on our backing layer and calling 80 syncCompositingStateSoon on WKCACFLayerRenderer as needed. Removed 81 updateRootLayerContents; that function was used to pass our backing 82 store to Core Animation, which we no longer do. Added m_backingLayer. 83 1 84 2011-01-17 Tony Gentilcore <tonyg@chromium.org> 2 85 -
trunk/Source/WebKit/win/WebCoreSupport/WebChromeClient.cpp
r75349 r75987 822 822 void WebChromeClient::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer) 823 823 { 824 m_webView->setRootChildLayer(graphicsLayer ? PlatformCALayer::platformCALayer(graphicsLayer->platformLayer()) : 0);824 m_webView->setRootChildLayer(graphicsLayer); 825 825 } 826 826 827 827 void WebChromeClient::scheduleCompositingLayerSync() 828 828 { 829 m_webView->s etRootLayerNeedsDisplay(true);829 m_webView->scheduleCompositingLayerSync(); 830 830 } 831 831 -
trunk/Source/WebKit/win/WebView.cpp
r75857 r75987 723 723 { 724 724 #if USE(ACCELERATED_COMPOSITING) 725 if (isAcceleratedCompositing()) 726 setRootLayerNeedsDisplay(); 725 if (isAcceleratedCompositing()) { 726 // The contentChanged, immediate, and repaintContentOnly parameters are all based on a non- 727 // compositing painting/scrolling model. 728 addToDirtyRegion(windowRect); 729 return; 730 } 727 731 #endif 728 732 … … 751 755 m_backingStoreBitmap.clear(); 752 756 m_backingStoreDirtyRegion.clear(); 753 #if USE(ACCELERATED_COMPOSITING)754 if (m_layerRenderer)755 m_layerRenderer->setBackingStoreDirty(false);756 #endif757 758 757 m_backingStoreSize.cx = m_backingStoreSize.cy = 0; 759 758 } … … 786 785 // http://webkit.org/b/29350. 787 786 787 #if USE(ACCELERATED_COMPOSITING) 788 if (isAcceleratedCompositing()) { 789 m_backingLayer->setNeedsDisplayInRect(dirtyRect); 790 return; 791 } 792 #endif 793 788 794 HRGN newRegion = ::CreateRectRgn(dirtyRect.x(), dirtyRect.y(), 789 795 dirtyRect.right(), dirtyRect.bottom()); … … 793 799 void WebView::addToDirtyRegion(HRGN newRegion) 794 800 { 801 #if USE(ACCELERATED_COMPOSITING) 802 ASSERT(!isAcceleratedCompositing()); 803 #endif 804 795 805 LOCAL_GDI_COUNTER(0, __FUNCTION__); 796 806 … … 803 813 m_backingStoreDirtyRegion = RefCountedHRGN::create(newRegion); 804 814 805 #if USE(ACCELERATED_COMPOSITING)806 if (m_layerRenderer)807 m_layerRenderer->setBackingStoreDirty(true);808 #endif809 810 815 if (m_uiDelegatePrivate) 811 816 m_uiDelegatePrivate->webViewDidInvalidate(this); … … 814 819 void WebView::scrollBackingStore(FrameView* frameView, int dx, int dy, const IntRect& scrollViewRect, const IntRect& clipRect) 815 820 { 821 #if USE(ACCELERATED_COMPOSITING) 822 ASSERT(!isAcceleratedCompositing()); 823 #endif 824 816 825 LOCAL_GDI_COUNTER(0, __FUNCTION__); 817 826 … … 867 876 if (m_layerRenderer) 868 877 m_layerRenderer->resize(); 878 if (m_backingLayer) { 879 m_backingLayer->setSize(newSize); 880 m_backingLayer->setNeedsDisplay(); 881 } 869 882 #endif 870 883 } … … 914 927 void WebView::updateBackingStore(FrameView* frameView, HDC dc, bool backingStoreCompletelyDirty, WindowsToPaint windowsToPaint) 915 928 { 929 #if USE(ACCELERATED_COMPOSITING) 930 ASSERT(!isAcceleratedCompositing()); 931 #endif 932 916 933 LOCAL_GDI_COUNTER(0, __FUNCTION__); 917 934 … … 948 965 949 966 m_backingStoreDirtyRegion.clear(); 950 #if USE(ACCELERATED_COMPOSITING)951 if (m_layerRenderer)952 m_layerRenderer->setBackingStoreDirty(false);953 #endif954 967 } 955 968 … … 965 978 { 966 979 LOCAL_GDI_COUNTER(0, __FUNCTION__); 980 981 #if USE(ACCELERATED_COMPOSITING) 982 if (isAcceleratedCompositing()) { 983 syncCompositingState(); 984 // Syncing might have taken us out of compositing mode. 985 if (isAcceleratedCompositing()) { 986 // FIXME: We need to paint into dc (if provided). <http://webkit.org/b/52578> 987 m_layerRenderer->paint(); 988 ::ValidateRect(m_viewWindow, 0); 989 return; 990 } 991 } 992 #endif 967 993 968 994 Frame* coreFrame = core(m_mainFrame); … … 1010 1036 updateBackingStore(frameView, bitmapDC, backingStoreCompletelyDirty, windowsToPaint); 1011 1037 1012 #if USE(ACCELERATED_COMPOSITING) 1013 if (!isAcceleratedCompositing()) { 1014 #endif 1015 // Now we blit the updated backing store 1016 IntRect windowDirtyRect = rcPaint; 1017 1018 // Apply the same heuristic for this update region too. 1019 Vector<IntRect> blitRects; 1020 if (region && regionType == COMPLEXREGION) 1021 getUpdateRects(region.get(), windowDirtyRect, blitRects); 1022 else 1023 blitRects.append(windowDirtyRect); 1024 1025 for (unsigned i = 0; i < blitRects.size(); ++i) 1026 paintIntoWindow(bitmapDC, hdc, blitRects[i]); 1027 #if USE(ACCELERATED_COMPOSITING) 1028 } else 1029 updateRootLayerContents(); 1030 #endif 1038 // Now we blit the updated backing store 1039 IntRect windowDirtyRect = rcPaint; 1040 1041 // Apply the same heuristic for this update region too. 1042 Vector<IntRect> blitRects; 1043 if (region && regionType == COMPLEXREGION) 1044 getUpdateRects(region.get(), windowDirtyRect, blitRects); 1045 else 1046 blitRects.append(windowDirtyRect); 1047 1048 for (unsigned i = 0; i < blitRects.size(); ++i) 1049 paintIntoWindow(bitmapDC, hdc, blitRects[i]); 1031 1050 1032 1051 ::SelectObject(bitmapDC, oldBitmap); … … 1046 1065 void WebView::paintIntoBackingStore(FrameView* frameView, HDC bitmapDC, const IntRect& dirtyRect, WindowsToPaint windowsToPaint) 1047 1066 { 1067 #if USE(ACCELERATED_COMPOSITING) 1068 ASSERT(!isAcceleratedCompositing()); 1069 #endif 1070 1048 1071 LOCAL_GDI_COUNTER(0, __FUNCTION__); 1049 1072 … … 1085 1108 void WebView::paintIntoWindow(HDC bitmapDC, HDC windowDC, const IntRect& dirtyRect) 1086 1109 { 1110 #if USE(ACCELERATED_COMPOSITING) 1111 ASSERT(!isAcceleratedCompositing()); 1112 #endif 1113 1087 1114 LOCAL_GDI_COUNTER(0, __FUNCTION__); 1088 1115 #if FLASH_WINDOW_REDRAW … … 2202 2229 #if USE(ACCELERATED_COMPOSITING) 2203 2230 if (webView->isAcceleratedCompositing()) 2204 webView-> setRootLayerNeedsDisplay();2231 webView->m_backingLayer->setNeedsDisplay(); 2205 2232 #endif 2206 2233 } … … 6232 6259 6233 6260 #if USE(ACCELERATED_COMPOSITING) 6234 void WebView::setRootChildLayer( WebCore::PlatformCALayer* layer)6261 void WebView::setRootChildLayer(GraphicsLayer* layer) 6235 6262 { 6236 6263 setAcceleratedCompositing(layer ? true : false); 6237 if (m_layerRenderer) 6238 m_layerRenderer->setRootChildLayer(layer); 6264 if (!m_backingLayer) 6265 return; 6266 m_backingLayer->addChild(layer); 6267 } 6268 6269 void WebView::scheduleCompositingLayerSync() 6270 { 6271 if (!m_layerRenderer) 6272 return; 6273 m_layerRenderer->syncCompositingStateSoon(); 6239 6274 } 6240 6275 … … 6253 6288 m_layerRenderer->setHostWindow(m_viewWindow); 6254 6289 m_layerRenderer->createRenderer(); 6290 6291 // FIXME: We could perhaps get better performance by never allowing this layer to 6292 // become tiled (or choosing a higher-than-normal tiling threshold). 6293 // <http://webkit.org/b/52603> 6294 m_backingLayer = GraphicsLayer::create(this); 6295 m_backingLayer->setDrawsContent(true); 6296 m_backingLayer->setContentsOpaque(true); 6297 RECT clientRect; 6298 ::GetClientRect(m_viewWindow, &clientRect); 6299 m_backingLayer->setSize(IntRect(clientRect).size()); 6300 m_backingLayer->setNeedsDisplay(); 6301 6302 m_layerRenderer->setRootChildLayer(PlatformCALayer::platformCALayer(m_backingLayer->platformLayer())); 6303 6304 // We aren't going to be using our backing store while we're in accelerated compositing 6305 // mode. But don't delete it immediately, in case we switch out of accelerated 6306 // compositing mode soon (e.g., if we're only compositing for a :hover animation). 6307 deleteBackingStoreSoon(); 6255 6308 } 6256 6309 } else { 6257 6310 m_layerRenderer = 0; 6311 m_backingLayer = 0; 6258 6312 m_isAcceleratedCompositing = false; 6259 6313 } 6260 }6261 6262 void releaseBackingStoreCallback(void* info, const void* data, size_t size)6263 {6264 // Release the backing store bitmap previously retained by updateRootLayerContents().6265 ASSERT(info);6266 if (info)6267 static_cast<RefCountedHBITMAP*>(info)->deref();6268 }6269 6270 void WebView::updateRootLayerContents()6271 {6272 if (!m_backingStoreBitmap || !m_layerRenderer)6273 return;6274 6275 // Get the backing store into a CGImage6276 BITMAP bitmap;6277 GetObject(m_backingStoreBitmap->handle(), sizeof(bitmap), &bitmap);6278 size_t bmSize = bitmap.bmWidthBytes * bitmap.bmHeight;6279 RetainPtr<CGDataProviderRef> cgData(AdoptCF,6280 CGDataProviderCreateWithData(static_cast<void*>(m_backingStoreBitmap.get()),6281 bitmap.bmBits, bmSize,6282 releaseBackingStoreCallback));6283 RetainPtr<CGColorSpaceRef> space(AdoptCF, CGColorSpaceCreateDeviceRGB());6284 RetainPtr<CGImageRef> backingStoreImage(AdoptCF, CGImageCreate(bitmap.bmWidth, bitmap.bmHeight,6285 8, bitmap.bmBitsPixel,6286 bitmap.bmWidthBytes, space.get(),6287 kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,6288 cgData.get(), 0, false,6289 kCGRenderingIntentDefault));6290 6291 // Retain the backing store bitmap so that it is not deleted by deleteBackingStore()6292 // while still in use within CA. When CA is done with the bitmap, it will6293 // call releaseBackingStoreCallback(), which will release the backing store bitmap.6294 m_backingStoreBitmap->ref();6295 6296 // Hand the CGImage to CACF for compositing6297 if (m_nextDisplayIsSynchronous) {6298 m_layerRenderer->setRootContentsAndDisplay(backingStoreImage.get());6299 m_nextDisplayIsSynchronous = false;6300 } else6301 m_layerRenderer->setRootContents(backingStoreImage.get());6302 6314 } 6303 6315 … … 6459 6471 6460 6472 #if USE(ACCELERATED_COMPOSITING) 6473 void WebView::notifyAnimationStarted(const GraphicsLayer*, double) 6474 { 6475 // We never set any animations on our backing layer. 6476 ASSERT_NOT_REACHED(); 6477 } 6478 6479 void WebView::notifySyncRequired(const GraphicsLayer*) 6480 { 6481 scheduleCompositingLayerSync(); 6482 } 6483 6484 void WebView::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const IntRect& inClip) 6485 { 6486 Frame* frame = core(m_mainFrame); 6487 if (!frame) 6488 return; 6489 6490 context.save(); 6491 context.clip(inClip); 6492 frame->view()->paint(&context, inClip); 6493 context.restore(); 6494 } 6495 6496 bool WebView::showDebugBorders() const 6497 { 6498 return m_page->settings()->showDebugBorders(); 6499 } 6500 6501 bool WebView::showRepaintCounter() const 6502 { 6503 return m_page->settings()->showRepaintCounter(); 6504 } 6505 6461 6506 bool WebView::shouldRender() const 6462 6507 { … … 6480 6525 { 6481 6526 Frame* coreFrame = core(m_mainFrame); 6482 if (coreFrame && coreFrame->view()) 6483 coreFrame->view()->syncCompositingStateRecursive(); 6527 if (!coreFrame) 6528 return; 6529 FrameView* view = coreFrame->view(); 6530 if (!view) 6531 return; 6532 if (!m_backingLayer) 6533 return; 6534 6535 view->updateLayoutAndStyleIfNeededRecursive(); 6536 6537 // Updating layout might have taken us out of compositing mode. 6538 if (m_backingLayer) 6539 m_backingLayer->syncCompositingStateForThisLayerOnly(); 6540 6541 view->syncCompositingStateRecursive(); 6484 6542 } 6485 6543 -
trunk/Source/WebKit/win/WebView.h
r75262 r75987 71 71 , WebCore::WindowMessageListener 72 72 #if USE(ACCELERATED_COMPOSITING) 73 , WebCore::GraphicsLayerClient 73 74 , WebCore::WKCACFLayerRendererClient 74 75 #endif … … 905 906 906 907 #if USE(ACCELERATED_COMPOSITING) 907 void setRootLayerNeedsDisplay(bool sync = false) 908 { 909 if (m_layerRenderer) 910 m_layerRenderer->setNeedsDisplay(sync); 911 } 912 void setRootChildLayer(WebCore::PlatformCALayer*); 908 void scheduleCompositingLayerSync(); 909 void setRootChildLayer(WebCore::GraphicsLayer*); 913 910 #endif 914 911 … … 944 941 945 942 #if USE(ACCELERATED_COMPOSITING) 943 // GraphicsLayerClient 944 virtual void notifyAnimationStarted(const WebCore::GraphicsLayer*, double time); 945 virtual void notifySyncRequired(const WebCore::GraphicsLayer*); 946 virtual void paintContents(const WebCore::GraphicsLayer*, WebCore::GraphicsContext&, WebCore::GraphicsLayerPaintingPhase, const WebCore::IntRect& inClip); 947 virtual bool showDebugBorders() const; 948 virtual bool showRepaintCounter() const; 949 946 950 // WKCACFLayerRendererClient 947 951 virtual bool shouldRender() const; … … 1053 1057 bool isAcceleratedCompositing() const { return m_isAcceleratedCompositing; } 1054 1058 void setAcceleratedCompositing(bool); 1055 void updateRootLayerContents();1056 1059 void layerRendererBecameVisible(); 1057 1060 1058 1061 OwnPtr<WebCore::WKCACFLayerRenderer> m_layerRenderer; 1062 OwnPtr<WebCore::GraphicsLayer> m_backingLayer; 1059 1063 bool m_isAcceleratedCompositing; 1060 1064 #endif
Note: See TracChangeset
for help on using the changeset viewer.