Reviewed and partially fixed by Tim Hatcher.
authoradele@apple.com <adele@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 11 Dec 2007 07:24:17 +0000 (07:24 +0000)
committeradele@apple.com <adele@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 11 Dec 2007 07:24:17 +0000 (07:24 +0000)
        Remaining part of fix for <rdar://problem/5633400>
        Transformed <video> is not clipped correctly until a repaint is forced

        Replace the implementation of a QTKit method to avoid repaints from the NSView system associated with the QTMovie
        from clobbering the WebCore repaints.

        * html/HTMLMediaElement.cpp: (WebCore::HTMLMediaElement::mediaPlayerRepaint): Added.
        * html/HTMLMediaElement.h:
        * platform/graphics/MediaPlayer.cpp: (WebCore::MediaPlayer::repaint): Added.
        * platform/graphics/MediaPlayer.h: (WebCore::MediaPlayerClient::mediaPlayerRepaint): Added.

        * platform/graphics/mac/MediaPlayerPrivateQTKit.h:
        * platform/graphics/mac/MediaPlayerPrivateQTKit.mm:
        (method_setImplementation): Added for Tiger.

        (WebCore::MediaPlayerPrivate::~MediaPlayerPrivate): Call detachQTMovieView, which now does more cleanup.
        (WebCore::MediaPlayerPrivate::cancelLoad): ditto.
        (WebCore::MediaPlayerPrivate::setVisible): ditto.
        (WebCore::MediaPlayerPrivate::detachQTMovieView): Clear the delegate as well as m_qtMovieView pointer.

        (WebCore::MediaPlayerPrivate::repaint): Added.  Triggers a repaint on the video renderer.
        (-[WebCoreMovieObserver repaint]): ditto.

        (WebCore::mainThreadSetNeedsDisplay): Added.
         Does a WebCore repaint instead of going through the view repaint system for QTMovieView.
        (WebCore::MediaPlayerPrivate::createQTMovieView): Replace the implementation of _mainThreadSetNeedsDisplay.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@28610 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/html/HTMLMediaElement.cpp
WebCore/html/HTMLMediaElement.h
WebCore/platform/graphics/MediaPlayer.cpp
WebCore/platform/graphics/MediaPlayer.h
WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm

index c737b2e..5990c13 100644 (file)
@@ -1,3 +1,34 @@
+2007-12-10  Adele Peterson  <adele@apple.com>
+
+        Reviewed and partially fixed by Tim Hatcher.
+
+        Remaining part of fix for <rdar://problem/5633400>
+        Transformed <video> is not clipped correctly until a repaint is forced
+
+        Replace the implementation of a QTKit method to avoid repaints from the NSView system associated with the QTMovie
+        from clobbering the WebCore repaints.
+
+        * html/HTMLMediaElement.cpp: (WebCore::HTMLMediaElement::mediaPlayerRepaint): Added.
+        * html/HTMLMediaElement.h:
+        * platform/graphics/MediaPlayer.cpp: (WebCore::MediaPlayer::repaint): Added.
+        * platform/graphics/MediaPlayer.h: (WebCore::MediaPlayerClient::mediaPlayerRepaint): Added.
+
+        * platform/graphics/mac/MediaPlayerPrivateQTKit.h:
+        * platform/graphics/mac/MediaPlayerPrivateQTKit.mm:
+        (method_setImplementation): Added for Tiger.
+
+        (WebCore::MediaPlayerPrivate::~MediaPlayerPrivate): Call detachQTMovieView, which now does more cleanup.
+        (WebCore::MediaPlayerPrivate::cancelLoad): ditto.
+        (WebCore::MediaPlayerPrivate::setVisible): ditto.
+        (WebCore::MediaPlayerPrivate::detachQTMovieView): Clear the delegate as well as m_qtMovieView pointer.
+
+        (WebCore::MediaPlayerPrivate::repaint): Added.  Triggers a repaint on the video renderer.
+        (-[WebCoreMovieObserver repaint]): ditto.
+
+        (WebCore::mainThreadSetNeedsDisplay): Added.
+         Does a WebCore repaint instead of going through the view repaint system for QTMovieView.
+        (WebCore::MediaPlayerPrivate::createQTMovieView): Replace the implementation of _mainThreadSetNeedsDisplay.
+
 2007-12-10  Geoffrey Garen  <ggaren@apple.com>
 
         Reviewed by Sam Weinig.
index a76c6fd..1aa50ba 100644 (file)
@@ -918,6 +918,12 @@ void HTMLMediaElement::mediaPlayerCuePointReached(MediaPlayer*, float cueTime)
     }      
 }
 
+void HTMLMediaElement::mediaPlayerRepaint(MediaPlayer*)
+{
+    if (renderer())
+        renderer()->repaint();
+}
+
 void HTMLMediaElement::addCuePoint(float time, VoidCallback* voidCallback, bool pause)
 {
     if (time < 0 || !isfinite(time))
index 271fb1a..3235366 100644 (file)
@@ -142,7 +142,8 @@ private: // MediaPlayerObserver
     virtual void mediaPlayerTimeChanged(MediaPlayer*);
     virtual void mediaPlayerVolumeChanged(MediaPlayer*);
     virtual void mediaPlayerCuePointReached(MediaPlayer*, float cueTime);
-        
+    virtual void mediaPlayerRepaint(MediaPlayer*);
+
 private:
     void loadTimerFired(Timer<HTMLMediaElement>*);
     void asyncEventTimerFired(Timer<HTMLMediaElement>*);
index 62c17fd..307ba3f 100644 (file)
@@ -277,5 +277,11 @@ void MediaPlayer::cuePointReached(float cueTime)
         m_mediaPlayerClient->mediaPlayerCuePointReached(this, cueTime);
 }
 
+void MediaPlayer::repaint()
+{
+    if (m_mediaPlayerClient)
+        m_mediaPlayerClient->mediaPlayerRepaint(this);
+}
+
 }
 #endif
index 7ea0978..4c324a8 100644 (file)
@@ -51,6 +51,7 @@ public:
     virtual void mediaPlayerVolumeChanged(MediaPlayer*) { }
     virtual void mediaPlayerTimeChanged(MediaPlayer*) { }
     virtual void mediaPlayerCuePointReached(MediaPlayer*, float cueTime) { }
+    virtual void mediaPlayerRepaint(MediaPlayer*) { }
 };
 
 class MediaPlayer : Noncopyable {
@@ -122,6 +123,8 @@ public:
     void timeChanged();
     void cuePointReached(float cueTime);
 
+    void repaint();
+    
 private:
         
     friend class MediaPlayerPrivate;
index e65acb4..2b0d56f 100644 (file)
@@ -97,6 +97,7 @@ public:
     void volumeChanged();
     void didEnd();
     
+    void repaint();
     void paint(GraphicsContext*, const IntRect&);
     
     static void getSupportedTypes(HashSet<String>& types);
@@ -104,6 +105,7 @@ public:
 private:
     void createQTMovie(const String& url);
     void createQTMovieView();
+    void detachQTMovieView();
     QTTime createQTTime(float time) const;
     
     void updateStates();
index 4ce5ac8..bd417fb 100644 (file)
 #import <QTKit/QTKit.h>
 #import <objc/objc-runtime.h>
 
+#ifdef BUILDING_ON_TIGER
+static IMP method_setImplementation(Method m, IMP imp)
+{
+    IMP result = m->method_imp;
+    m->method_imp = imp;
+    return result;
+}
+#endif
+
 SOFT_LINK_FRAMEWORK(QTKit)
 
 SOFT_LINK(QTKit, QTMakeTime, QTTime, (long long timeValue, long timeScale), (timeValue, timeScale))
@@ -93,6 +102,7 @@ using namespace std;
 }
 -(id)initWithCallback:(MediaPlayerPrivate*)callback;
 -(void)disconnect;
+-(void)repaint;
 -(void)setDelayCallbacks:(BOOL)shouldDelay;
 -(void)loadStateChanged:(NSNotification *)notification;
 -(void)rateChanged:(NSNotification *)notification;
@@ -123,8 +133,8 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
 
 MediaPlayerPrivate::~MediaPlayerPrivate()
 {
-    if (m_qtMovieView)
-        [m_qtMovieView.get() removeFromSuperview];
+    detachQTMovieView();
+
     [[NSNotificationCenter defaultCenter] removeObserver:m_objcObserver.get()];
     [m_objcObserver.get() disconnect];
 }
@@ -171,17 +181,44 @@ void MediaPlayerPrivate::createQTMovie(const String& url)
                                                object:m_qtMovie.get()];
 }
 
+static void mainThreadSetNeedsDisplay(id self, SEL _cmd)
+{
+    id movieView = [self superview];
+    ASSERT(!movieView || [movieView isKindOfClass:[QTMovieView class]]);
+    if (!movieView || ![movieView isKindOfClass:[QTMovieView class]])
+        return;
+
+    WebCoreMovieObserver* delegate = [movieView delegate];
+    ASSERT(!delegate || [delegate isKindOfClass:[WebCoreMovieObserver class]]);
+    if (!delegate || ![delegate isKindOfClass:[WebCoreMovieObserver class]])
+        return;
+
+    [delegate repaint];
+}
+
 void MediaPlayerPrivate::createQTMovieView()
 {
-    if (m_qtMovieView) {
-        [m_qtMovieView.get() removeFromSuperview];
-        m_qtMovieView = nil;
-    }
+    detachQTMovieView();
+
     if (!m_player->m_parentWidget || !m_qtMovie)
         return;
+
+    static bool addedCustomMethods = false;
+    if (!addedCustomMethods) {
+        Class QTMovieContentViewClass = NSClassFromString(@"QTMovieContentView");
+        ASSERT(QTMovieContentViewClass);
+
+        Method mainThreadSetNeedsDisplayMethod = class_getInstanceMethod(QTMovieContentViewClass, @selector(_mainThreadSetNeedsDisplay));
+        ASSERT(mainThreadSetNeedsDisplayMethod);
+
+        method_setImplementation(mainThreadSetNeedsDisplayMethod, reinterpret_cast<IMP>(mainThreadSetNeedsDisplay));
+        addedCustomMethods = true;
+    }
+
     m_qtMovieView.adoptNS([[QTMovieView alloc] initWithFrame:m_player->rect()]);
     NSView* parentView = static_cast<ScrollView*>(m_player->m_parentWidget)->getDocumentView();
     [parentView addSubview:m_qtMovieView.get()];
+    [m_qtMovieView.get() setDelegate:m_objcObserver.get()];
     [m_qtMovieView.get() setMovie:m_qtMovie.get()];
     [m_qtMovieView.get() setControllerVisible:NO];
     [m_qtMovieView.get() setPreservesAspectRatio:YES];
@@ -190,6 +227,15 @@ void MediaPlayerPrivate::createQTMovieView()
     wkQTMovieViewSetDrawSynchronously(m_qtMovieView.get(), YES);
 }
 
+void MediaPlayerPrivate::detachQTMovieView()
+{
+    if (m_qtMovieView) {
+        [m_qtMovieView.get() setDelegate:nil];
+        [m_qtMovieView.get() removeFromSuperview];
+        m_qtMovieView = nil;
+    }
+}
+
 QTTime MediaPlayerPrivate::createQTTime(float time) const
 {
     if (!m_qtMovie)
@@ -476,10 +522,7 @@ void MediaPlayerPrivate::cancelLoad()
     if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
         return;
     
-    if (m_qtMovieView) {
-        [m_qtMovieView.get() removeFromSuperview];
-        m_qtMovieView = nil;
-    }
+    detachQTMovieView();
     m_qtMovie = nil;
     
     updateStates();
@@ -570,10 +613,13 @@ void MediaPlayerPrivate::setVisible(bool b)
 {
     if (b)
         createQTMovieView();
-    else if (m_qtMovieView) {
-        [m_qtMovieView.get() removeFromSuperview];
-        m_qtMovieView = nil;
-    }
+    else
+        detachQTMovieView();
+}
+
+void MediaPlayerPrivate::repaint()
+{
+    m_player->repaint();
 }
 
 void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r)
@@ -628,6 +674,14 @@ void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
     m_callback = 0;
 }
 
+-(void)repaint
+{
+    if (m_delayCallbacks)
+        [self performSelector:_cmd withObject:nil afterDelay:0.];
+    else if (m_callback)
+        m_callback->repaint();
+}
+
 - (void)loadStateChanged:(NSNotification *)notification
 {
     if (m_delayCallbacks)