← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~j-corwin/openlp/render into lp:openlp

 

Jonathan Corwin has proposed merging lp:~j-corwin/openlp/render into lp:openlp.

Requested reviews:
  OpenLP Core (openlp-core)


Speed up transitions (hopefully...)
Change QtWebView to QtGraphicsWebView, since in some circumstances can apparently improve performance, and is the recommended way forward.
Rework html, replace tables with div's, and remove redundant div's where possible or where qtwebkit version allows, in order to improve performance.

-- 
https://code.launchpad.net/~j-corwin/openlp/render/+merge/34490
Your team OpenLP Core is requested to review the proposed merge of lp:~j-corwin/openlp/render into lp:openlp.
=== modified file 'openlp/core/lib/htmlbuilder.py'
--- openlp/core/lib/htmlbuilder.py	2010-08-29 14:42:47 +0000
+++ openlp/core/lib/htmlbuilder.py	2010-09-02 21:09:42 +0000
@@ -24,6 +24,8 @@
 # Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
 ###############################################################################
 
+from PyQt4 import QtWebKit
+
 from openlp.core.lib import image_to_byte
 
 HTMLSRC = u"""
@@ -39,7 +41,7 @@
 body {
     background-color: black;
 }
-.dim {
+.size {
     position: absolute;
     left: 0px;
     top: 0px;
@@ -51,6 +53,9 @@
     background-color: black;
     display: none;
 }
+#image {
+    z-index:1;
+}
 #video {
     z-index:2;
 }
@@ -136,8 +141,12 @@
         }
         document.getElementById('black').style.display = black;
         document.getElementById('lyricsmain').style.visibility = lyrics;
-        document.getElementById('lyricsoutline').style.visibility = lyrics;
-        document.getElementById('lyricsshadow').style.visibility = lyrics;
+        outline = document.getElementById('lyricsoutline')
+        if(outline)
+            outline.style.visibility = lyrics;
+        shadow = document.getElementById('lyricsshadow')
+        if(shadow)
+            shadow.style.visibility = lyrics;
         document.getElementById('footer').style.visibility = lyrics;
         var vid = document.getElementById('video');
         if(vid.src != ''){
@@ -156,7 +165,7 @@
             return 0;
         }
         if(position == ''){
-            position = window.getComputedStyle(text, '').verticalAlign;
+            position = getComputedStyle(text, '').verticalAlign;
         }
         switch(position)
         {
@@ -181,111 +190,61 @@
     }
 
     function show_text(newtext){
-        var text1 = document.getElementById('lyricsmain');
-        var texto1 = document.getElementById('lyricsoutline');
-        var texts1 = document.getElementById('lyricsshadow');
+        if(timer != null)
+            clearTimeout(timer);
+        text_fade('lyricsmain', newtext);        
+        text_fade('lyricsoutline', newtext);
+        text_fade('lyricsshadow', newtext);
+        if(text_opacity()==1) return;
+        timer = setTimeout(function(){
+            show_text(newtext);
+        }, 100);
+    }
+
+    function text_fade(id, newtext){
+        /*
+        Using -webkit-transition: opacity 1s linear; would have been preferred
+        but it isn't currently quick enough when animating multiple layers of
+        large areas of large text. Therefore do it manually as best we can.
+        Hopefully in the future we can revisit and do more interesting
+        transitions using -webkit-transition and -webkit-transform.
+        However we need to ensure interrupted transitions (quickly change 2
+        slides) still looks pretty and is zippy.
+        */
+        var text = document.getElementById(id);
+        if(text==null) return;
         if(!transition){
-            text1.innerHTML = newtext;
-            texto1.innerHTML = newtext;
-            texts1.innerHTML = newtext;
+            text.innerHTML = newtext;
             return;
         }
-        var text2 = document.getElementById('lyricsmain2');
-        var texto2 = document.getElementById('lyricsoutline2');
-        var texts2 = document.getElementById('lyricsshadow2');
-        if((text2.style.opacity == '')||(parseFloat(text2.style.opacity) < 0.5))
-        {
-            text2.innerHTML = text1.innerHTML;
-            text2.style.opacity = text1.style.opacity;
-            texto2.innerHTML = text1.innerHTML;
-            texto2.style.opacity = text1.style.opacity;
-            texts2.innerHTML = text1.innerHTML;
-            texts2.style.opacity = text1.style.opacity;
-        }
-        text1.style.opacity = 0;
-        text1.innerHTML = newtext;
-        texto1.style.opacity = 0;
-        texto1.innerHTML = newtext;
-        texts1.style.opacity = 0;
-        texts1.innerHTML = newtext;
-        // For performance reasons, we'll not animate the shadow for now
-        texts2.style.opacity = 0;
-        if(timer != null)
-            clearTimeout(timer);
-        timer = setTimeout('text_fade()', 50);
-    }
-
-    function text_fade(){
-        var text1 = document.getElementById('lyricsmain');
-        var texto1 = document.getElementById('lyricsoutline');
-        var texts1 = document.getElementById('lyricsshadow');
-        var text2 = document.getElementById('lyricsmain2');
-        var texto2 = document.getElementById('lyricsoutline2');
-        var texts2 = document.getElementById('lyricsshadow2');
-        if(parseFloat(text1.style.opacity) < 1){
-            text1.style.opacity = parseFloat(text1.style.opacity) + 0.1;
-            texto1.style.opacity = parseFloat(texto1.style.opacity) + 0.1;
-            // Don't animate shadow (performance)
-            //texts1.style.opacity = parseFloat(texts1.style.opacity) + 0.1;
-        }
-        if(parseFloat(text2.style.opacity) > 0){
-            text2.style.opacity = parseFloat(text2.style.opacity) - 0.1;
-            texto2.style.opacity = parseFloat(texto2.style.opacity) - 0.1;
-            // Don't animate shadow (performance)
-            //texts2.style.opacity = parseFloat(texts2.style.opacity) - 0.1;
-        }
-        if((parseFloat(text1.style.opacity) < 1) ||
-            (parseFloat(text2.style.opacity) > 0)){
-            t = setTimeout('text_fade()', 50);
+        if(text.style.opacity=='') text.style.opacity = 1;
+        if(newtext==text.innerHTML){
+            text.style.opacity = parseFloat(text.style.opacity) + 0.3;
         } else {
-            text1.style.opacity = 1;
-            texto1.style.opacity = 1;
-            texts1.style.opacity = 1;
-            text2.style.opacity = 0;
-            texto2.style.opacity = 0;
-            texts2.style.opacity = 0;
+            text.style.opacity -= 0.3;
+            if(text.style.opacity<=0.1){
+                text.innerHTML = newtext;
+            }
         }
     }
 
+    function text_opacity(){
+        var text = document.getElementById('lyricsmain');
+        return getComputedStyle(text, '').opacity;
+    }
+    
     function show_text_complete(){
-       return (document.getElementById('lyricsmain').style.opacity == 1);
+        return (text_opacity()==1);
     }
 </script>
 </head>
 <body>
-<!--
-Using tables, rather than div's to make use of the vertical-align style that
-doesn't work on div's. This avoids the need to do positioning manually which
-could get messy when changing verses esp. with transitions
-
-Would prefer to use a single table and make use of -webkit-text-fill-color
--webkit-text-stroke and text-shadow styles, but they have problems working/
-co-operating in qwebkit. https://bugs.webkit.org/show_bug.cgi?id=43187
-Therefore one table for text, one for outline and one for shadow.
--->
-<table class="lyricstable lyricscommon">
-    <tr><td id="lyricsmain" class="lyrics"></td></tr>
-</table>
-<table class="lyricsoutlinetable lyricscommon">
-    <tr><td id="lyricsoutline" class="lyricsoutline lyrics"></td></tr>
-</table>
-<table class="lyricsshadowtable lyricscommon">
-    <tr><td id="lyricsshadow" class="lyricsshadow lyrics"></td></tr>
-</table>
-<table class="lyricstable lyricscommon">
-    <tr><td id="lyricsmain2" class="lyrics"></td></tr>
-</table>
-<table class="lyricsoutlinetable lyricscommon">
-    <tr><td id="lyricsoutline2" class="lyricsoutline lyrics"></td></tr>
-</table>
-<table class="lyricsshadowtable lyricscommon">
-    <tr><td id="lyricsshadow2" class="lyricsshadow lyrics"></td></tr>
-</table>
+<img id="image" class="size" src="%s" />
+<video id="video" class="size"></video>
+%s
+<div id="footer" class="footer"></div>
+<div id="black" class="size"></div>
 <div id="alert" style="visibility:hidden;"></div>
-<div id="footer" class="footer"></div>
-<video class="dim" id="video"></video>
-<div class="dim" id="black"></div>
-<img class="dim" id="image" src="%s" />
 </body>
 </html>
     """
@@ -300,7 +259,13 @@
         Current display information
     `alert`
         Alert display display information
+    `islive`
+        Item is going live, rather than preview/theme building
     """
+    try:
+        webkitvers = float(QtWebKit.qWebKitVersion())
+    except AttributeError:
+        webkitvers = 0
     width = screen[u'size'].width()
     height = screen[u'size'].height()
     theme = item.themedata
@@ -309,83 +274,143 @@
     else:
         image = u''
     html = HTMLSRC % (width, height,
-        build_alert(alert, width),
-        build_footer(item),
-        build_lyrics(item),
+        build_alert_css(alert, width),
+        build_footer_css(item),
+        build_lyrics_css(item, webkitvers),
         u'true' if theme and theme.display_slideTransition and islive \
             else u'false',
-        image)
+        image, 
+        build_lyrics_html(item, webkitvers))
     return html
 
-def build_lyrics(item):
+def build_lyrics_css(item, webkitvers):
     """
-    Build the video display div
+    Build the video display css
 
     `item`
         Service Item containing theme and location information
+    
+    `webkitvers`
+        The version of qtwebkit we're using
+
     """
     style = """
-    .lyricscommon { position: absolute;  %s }
-    .lyricstable { z-index:4;  %s }
-    .lyricsoutlinetable { z-index:3; %s }
-    .lyricsshadowtable { z-index:2; %s }
-    .lyrics { %s }
-    .lyricsoutline { %s }
-    .lyricsshadow { %s }
+.lyricstable { 
+    z-index:4; 
+    position: absolute; 
+    display: table; 
+    %s 
+}
+.lyricscell { 
+    display:table-cell; 
+    word-wrap: break-word; 
+    %s
+}
+.lyricsmain { 
+%s 
+}
+.lyricsoutline { 
+%s 
+}
+.lyricsshadow { 
+%s 
+}
      """
     theme = item.themedata
-    lyricscommon = u''
     lyricstable = u''
-    outlinetable = u''
-    shadowtable = u''
     lyrics = u''
-    outline = u'display: none;'
-    shadow = u'display: none;'
+    lyricsmain = u''
+    outline = u''
+    shadow = u''
     if theme:
-        lyricscommon =  u'width: %spx; height: %spx; word-wrap: break-word;  ' \
-            u'font-family: %s; font-size: %spt; color: %s; line-height: %d%%;' \
-            % (item.main.width(), item.main.height(), theme.font_main_name,
-            theme.font_main_proportion, theme.font_main_color,
-            100 + int(theme.font_main_line_adjustment))
         lyricstable = u'left: %spx; top: %spx;' % \
             (item.main.x(), item.main.y())
-        outlinetable = u'left: %spx; top: %spx;' % \
-            (item.main.x(), item.main.y())
-        shadowtable = u'left: %spx; top: %spx;' % \
-            (item.main.x() + float(theme.display_shadow_size),
-            item.main.y() + float(theme.display_shadow_size))
-        align = u''
         if theme.display_horizontalAlign == 2:
-            align = u'text-align:center;'
+            align = u'center'
         elif theme.display_horizontalAlign == 1:
-            align = u'text-align:right;'
+            align = u'right'
         else:
-            align = u'text-align:left;'
+            align = u'left'
         if theme.display_verticalAlign == 2:
-            valign = u'vertical-align:bottom;'
+            valign = u'bottom'
         elif theme.display_verticalAlign == 1:
-            valign = u'vertical-align:middle;'
+            valign = u'middle'
         else:
-            valign = u'vertical-align:top;'
-        lyrics = u'%s %s' % (align, valign)
+            valign = u'top'
+        lyrics = u'width: %spx; height: %spx; text-align: %s; ' \
+            'vertical-align: %s; font-family: %s; font-size: %spt; ' \
+            'color: %s; line-height: %d%%;' % \
+            (item.main.width(), item.main.height(), align, valign, 
+            theme.font_main_name, theme.font_main_proportion, 
+            theme.font_main_color, 100 + int(theme.font_main_line_adjustment))
+        # For performance reasons we want to show as few DIV's as possible,
+        # especially when animating/transitions. 
+        # However some bugs in older versions of qtwebkit mean we need to 
+        # perform workarounds and add extra divs. Only do these when needed.
+        #
+        # Before 533.3 the webkit-text-fill colour wasn't displayed, only the 
+        # stroke (outline) color. So put stroke layer underneath the main text.
+        #
+        # Before 534.4 the webkit-text-stroke was sometimes out of alignment 
+        # with the fill, or normal text. letter-spacing=1 is workaround
+        # https://bugs.webkit.org/show_bug.cgi?id=44403
+        #
+        # Before 534.4 the text-shadow didn't get displayed when 
+        # webkit-text-stroke was used. So use an offset text layer underneath. 
+        # https://bugs.webkit.org/show_bug.cgi?id=19728
         if theme.display_outline:
-            lyricscommon += u' letter-spacing: 1px;'
-            outline = u'-webkit-text-stroke: %sem %s; ' % \
+            if webkitvers < 534.3:
+                lyrics += u' letter-spacing: 1px;'
+            outline = u' -webkit-text-stroke: %sem %s; ' \
+                '-webkit-text-fill-color: %s; ' % \
                 (float(theme.display_outline_size) / 16,
-                theme.display_outline_color)
-            if theme.display_shadow:
+                theme.display_outline_color, theme.font_main_color)
+            if webkitvers >= 533.3:
+                lyricsmain += outline
+            if theme.display_shadow and webkitvers < 534.3:
                 shadow = u'-webkit-text-stroke: %sem %s; ' \
-                    u'-webkit-text-fill-color: %s; ' % \
+                    u'-webkit-text-fill-color: %s; ' \
+                    u' padding-left: %spx; padding-top: %spx' % \
                     (float(theme.display_outline_size) / 16,
-                    theme.display_shadow_color, theme.display_shadow_color)
-        else:
-            if theme.display_shadow:
-                shadow = u'color: %s;' % (theme.display_shadow_color)
-    lyrics_html = style % (lyricscommon, lyricstable, outlinetable,
-        shadowtable, lyrics, outline, shadow)
-    return lyrics_html
+                    theme.display_shadow_color, theme.display_shadow_color, 
+                    theme.display_shadow_size, theme.display_shadow_size)
+        if theme.display_shadow and \
+            (not theme.display_outline or webkitvers >= 534.3):
+            lyricsmain += u' text-shadow: %s %spx %spx;' % \
+                (theme.display_shadow_color, theme.display_shadow_size,
+                theme.display_shadow_size)
+    lyrics_css = style % (lyricstable, lyrics, lyricsmain, outline, shadow)
+    return lyrics_css
+    
+def build_lyrics_html(item, webkitvers):
+    """
+    Build the HTML required to show the lyrics
 
-def build_footer(item):
+    `item`
+        Service Item containing theme and location information
+    
+    `webkitvers`
+        The version of qtwebkit we're using
+    """
+    # Bugs in some versions of QtWebKit mean we sometimes need additional 
+    # divs for outline and shadow, since the CSS doesn't work.
+    # To support vertical alignment middle and bottom, nested div's using
+    # display:table/display:table-cell are required for each lyric block.
+    lyrics = u''
+    theme = item.themedata
+    if webkitvers < 534.4 and theme and theme.display_outline:
+        lyrics += u'<div class="lyricstable">' \
+            u'<div id="lyricsshadow" class="lyricscell lyricsshadow">' \
+            u'</div></div>'
+        if webkitvers < 533.3:
+            lyrics += u'<div class="lyricstable">' \
+                u'<div id="lyricsoutline" class="lyricscell lyricsoutline">' \
+                u'</div></div>'
+    lyrics += u'<div class="lyricstable">' \
+        u'<div id="lyricsmain" class="lyricscell lyricsmain"></div></div>'
+    return lyrics
+    
+def build_footer_css(item):
     """
     Build the display of the item footer
 
@@ -416,7 +441,7 @@
         theme.font_footer_proportion, theme.font_footer_color, align)
     return lyrics_html
 
-def build_alert(alertTab, width):
+def build_alert_css(alertTab, width):
     """
     Build the display of the footer
 
@@ -424,7 +449,7 @@
         Details from the Alert tab for fonts etc
     """
     style = """
-    width: %s;
+    width: %spx;
     vertical-align: %s;
     font-family: %s;
     font-size: %spt;

=== modified file 'openlp/core/ui/maindisplay.py'
--- openlp/core/ui/maindisplay.py	2010-08-29 19:29:45 +0000
+++ openlp/core/ui/maindisplay.py	2010-09-02 21:09:42 +0000
@@ -115,8 +115,11 @@
         self.screen = self.screens.current
         self.setVisible(False)
         self.setGeometry(self.screen[u'size'])
-        self.webView = QtWebKit.QWebView(self)
-        self.webView.setGeometry(0, 0, self.screen[u'size'].width(), \
+        self.scene = QtGui.QGraphicsScene()
+        self.setScene(self.scene)
+        self.webView = QtWebKit.QGraphicsWebView()
+        self.scene.addItem(self.webView)
+        self.webView.resize(self.screen[u'size'].width(), \
             self.screen[u'size'].height())
         self.page = self.webView.page()
         self.frame = self.page.mainFrame()


Follow ups