← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~googol/openlp/html-clean-up into lp:openlp

 

Andreas Preikschat has proposed merging lp:~googol/openlp/html-clean-up into lp:openlp.

Requested reviews:
  Tim Bentley (trb143)

For more details, see:
https://code.launchpad.net/~googol/openlp/html-clean-up/+merge/190573

Hello,

I started this sommmmme time ago and just found it...

- removed (outline/shaddow) workarounds from html builder
- removed code from phonon player which should not be there (copy-paste error?)

OS.......Version
----------------
Fedora...537.21
MAC......534.34
Arch.....537.21
Windows..534.34

The workaround were for 534.3 and below, so all major platforms should be ok with this change.
-- 
https://code.launchpad.net/~googol/openlp/html-clean-up/+merge/190573
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp/core/lib/htmlbuilder.py'
--- openlp/core/lib/htmlbuilder.py	2013-08-31 18:17:38 +0000
+++ openlp/core/lib/htmlbuilder.py	2013-10-11 09:54:38 +0000
@@ -26,7 +26,372 @@
 # with this program; if not, write to the Free Software Foundation, Inc., 59  #
 # Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
 ###############################################################################
-
+"""
+This module is responsible for generating the HTML for :class:`~openlp.core.ui.maindisplay`. The ``build_html`` function
+is the function which has to be called from outside. The generated and returned HTML will look similar to this::
+
+        <!DOCTYPE html>
+        <html>
+        <head>
+        <title>OpenLP Display</title>
+        <style>
+        *{
+            margin: 0;
+            padding: 0;
+            border: 0;
+            overflow: hidden;
+            -webkit-user-select: none;
+        }
+        body {
+            background-color: #000000;
+        }
+        .size {
+            position: absolute;
+            left: 0px;
+            top: 0px;
+            width: 100%;
+            height: 100%;
+        }
+        #black {
+            z-index: 8;
+            background-color: black;
+            display: none;
+        }
+        #bgimage {
+            z-index: 1;
+        }
+        #image {
+            z-index: 2;
+        }
+
+        #videobackboard {
+            z-index:3;
+            background-color: #000000;
+        }
+        #video {
+            background-color: #000000;
+            z-index:4;
+        }
+
+        #flash {
+            z-index:5;
+        }
+
+            #alert {
+                position: absolute;
+                left: 0px;
+                top: 0px;
+                z-index: 10;
+                width: 100%;
+                vertical-align: bottom;
+                font-family: DejaVu Sans;
+                font-size: 40pt;
+                color: #ffffff;
+                background-color: #660000;
+                word-wrap: break-word;
+            }
+
+        #footer {
+            position: absolute;
+            z-index: 6;
+
+            left: 10px;
+            bottom: 0px;
+            width: 1580px;
+            font-family: Nimbus Sans L;
+            font-size: 12pt;
+            color: #FFFFFF;
+            text-align: left;
+            white-space: nowrap;
+
+        }
+        /* lyric css */
+
+        .lyricstable {
+            z-index: 5;
+            position: absolute;
+            display: table;
+            left: 10px; top: 0px;
+        }
+        .lyricscell {
+            display: table-cell;
+            word-wrap: break-word;
+            -webkit-transition: opacity 0.4s ease;
+            white-space:pre-wrap; word-wrap: break-word; text-align: left; vertical-align: top; font-family: Nimbus Sans L; font-size: 40pt; color: #FFFFFF; line-height: 100%; margin: 0;padding: 0; padding-bottom: 0; padding-left: 4px; width: 1580px; height: 810px;
+        }
+        .lyricsmain {
+             -webkit-text-stroke: 0.125em #000000; -webkit-text-fill-color: #FFFFFF;  text-shadow: #000000 5px 5px;
+        }
+
+        sup {
+            font-size: 0.6em;
+            vertical-align: top;
+            position: relative;
+            top: -0.3em;
+        }
+        </style>
+        <script>
+            var timer = null;
+            var transition = false;
+
+            function show_video(state, path, volume, loop, variable_value){
+                // Sometimes  video.currentTime stops slightly short of video.duration and video.ended is intermittent!
+
+                var video = document.getElementById('video');
+                if(volume != null){
+                    video.volume = volume;
+                }
+                switch(state){
+                    case 'load':
+                        video.src = 'file:///' + path;
+                        if(loop == true) {
+                            video.loop = true;
+                        }
+                        video.load();
+                        break;
+                    case 'play':
+                        video.play();
+                        break;
+                    case 'pause':
+                        video.pause();
+                        break;
+                    case 'stop':
+                        show_video('pause');
+                        video.currentTime = 0;
+                        break;
+                    case 'close':
+                        show_video('stop');
+                        video.src = '';
+                        break;
+                    case 'length':
+                        return video.duration;
+                    case 'current_time':
+                        return video.currentTime;
+                    case 'seek':
+                        video.currentTime = variable_value;
+                        break;
+                    case 'isEnded':
+                        return video.ended;
+                    case 'setVisible':
+                        video.style.visibility = variable_value;
+                        break;
+                    case 'setBackBoard':
+                        var back = document.getElementById('videobackboard');
+                        back.style.visibility = variable_value;
+                        break;
+               }
+            }
+
+            function getFlashMovieObject(movieName)
+            {
+                if (window.document[movieName]){
+                    return window.document[movieName];
+                }
+                if (document.embeds && document.embeds[movieName]){
+                    return document.embeds[movieName];
+                }
+            }
+
+            function show_flash(state, path, volume, variable_value){
+                var text = document.getElementById('flash');
+                var flashMovie = getFlashMovieObject("OpenLPFlashMovie");
+                var src = "src = 'file:///" + path + "'";
+                var view_parm = " wmode='opaque'" + " width='100%%'" + " height='100%%'";
+                var swf_parm = " name='OpenLPFlashMovie'" + " autostart='true' loop='false' play='true'" +
+                    " hidden='false' swliveconnect='true' allowscriptaccess='always'" + " volume='" + volume + "'";
+
+                switch(state){
+                    case 'load':
+                        text.innerHTML = "<embed " + src + view_parm + swf_parm + "/>";
+                        flashMovie = getFlashMovieObject("OpenLPFlashMovie");
+                        flashMovie.Play();
+                        break;
+                    case 'play':
+                        flashMovie.Play();
+                        break;
+                    case 'pause':
+                        flashMovie.StopPlay();
+                        break;
+                    case 'stop':
+                        flashMovie.StopPlay();
+                        tempHtml = text.innerHTML;
+                        text.innerHTML = '';
+                        text.innerHTML = tempHtml;
+                        break;
+                    case 'close':
+                        flashMovie.StopPlay();
+                        text.innerHTML = '';
+                        break;
+                    case 'length':
+                        return flashMovie.TotalFrames();
+                    case 'current_time':
+                        return flashMovie.CurrentFrame();
+                    case 'seek':
+        //                flashMovie.GotoFrame(variable_value);
+                        break;
+                    case 'isEnded':
+                        //TODO check flash end
+                        return false;
+                    case 'setVisible':
+                        text.style.visibility = variable_value;
+                        break;
+                }
+            }
+
+            function show_alert(alerttext, position){
+                var text = document.getElementById('alert');
+                text.innerHTML = alerttext;
+                if(alerttext == '') {
+                    text.style.visibility = 'hidden';
+                    return 0;
+                }
+                if(position == ''){
+                    position = getComputedStyle(text, '').verticalAlign;
+                }
+                switch(position)
+                {
+                    case 'top':
+                        text.style.top = '0px';
+                        break;
+                    case 'middle':
+                        text.style.top = ((window.innerHeight - text.clientHeight) / 2)
+                            + 'px';
+                        break;
+                    case 'bottom':
+                        text.style.top = (window.innerHeight - text.clientHeight)
+                            + 'px';
+                        break;
+                }
+                text.style.visibility = 'visible';
+                return text.clientHeight;
+            }
+
+            function update_css(align, font, size, color, bgcolor){
+                var text = document.getElementById('alert');
+                text.style.fontSize = size + "pt";
+                text.style.fontFamily = font;
+                text.style.color = color;
+                text.style.backgroundColor = bgcolor;
+                switch(align)
+                {
+                    case 'top':
+                        text.style.top = '0px';
+                        break;
+                    case 'middle':
+                        text.style.top = ((window.innerHeight - text.clientHeight) / 2)
+                            + 'px';
+                        break;
+                    case 'bottom':
+                        text.style.top = (window.innerHeight - text.clientHeight)
+                            + 'px';
+                        break;
+                }
+            }
+
+
+            function show_image(src){
+                var img = document.getElementById('image');
+                img.src = src;
+                if(src == '')
+                    img.style.display = 'none';
+                else
+                    img.style.display = 'block';
+            }
+
+            function show_blank(state){
+                var black = 'none';
+                var lyrics = '';
+                switch(state){
+                    case 'theme':
+                        lyrics = 'hidden';
+                        break;
+                    case 'black':
+                        black = 'block';
+                        break;
+                    case 'desktop':
+                        break;
+                }
+                document.getElementById('black').style.display = black;
+                document.getElementById('lyricsmain').style.visibility = lyrics;
+                document.getElementById('image').style.visibility = lyrics;
+                document.getElementById('footer').style.visibility = lyrics;
+            }
+
+            function show_footer(footertext){
+                document.getElementById('footer').innerHTML = footertext;
+            }
+
+            function show_text(new_text){
+                var match = /-webkit-text-fill-color:[^;"]+/gi;
+                if(timer != null)
+                    clearTimeout(timer);
+                /*
+                QtWebkit bug with outlines and justify causing outline alignment
+                problems. (Bug 859950) Surround each word with a <span> to workaround,
+                but only in this scenario.
+                */
+                var txt = document.getElementById('lyricsmain');
+                if(window.getComputedStyle(txt).textAlign == 'justify'){
+                    if(window.getComputedStyle(txt).webkitTextStrokeWidth != '0px'){
+                        new_text = new_text.replace(/(\s|&nbsp;)+(?![^<]*>)/g,
+                            function(match) {
+                                return '</span>' + match + '<span>';
+                            });
+                        new_text = '<span>' + new_text + '</span>';
+                    }
+                }
+                text_fade('lyricsmain', new_text);
+            }
+
+            function text_fade(id, new_text){
+                /*
+                Show the text.
+                */
+                var text = document.getElementById(id);
+                if(text == null) return;
+                if(!transition){
+                    text.innerHTML = new_text;
+                    return;
+                }
+                // Fade text out. 0.1 to minimize the time "nothing" is shown on the screen.
+                text.style.opacity = '0.1';
+                // Fade new text in after the old text has finished fading out.
+                timer = window.setTimeout(function(){_show_text(text, new_text)}, 400);
+            }
+
+            function _show_text(text, new_text) {
+                /*
+                Helper function to show the new_text delayed.
+                */
+                text.innerHTML = new_text;
+                text.style.opacity = '1';
+                // Wait until the text is completely visible. We want to save the timer id, to be able to call
+                // clearTimeout(timer) when the text has changed before finishing fading.
+                timer = window.setTimeout(function(){timer = null;}, 400);
+            }
+
+            function show_text_completed(){
+                return (timer == null);
+            }
+        </script>
+        </head>
+        <body>
+        <img id="bgimage" class="size" style="display:none;" />
+        <img id="image" class="size" style="display:none;" />
+
+        <div id="videobackboard" class="size" style="visibility:hidden"></div>
+        <video id="video" class="size" style="visibility:hidden" autobuffer preload></video>
+
+        <div id="flash" class="size" style="visibility:hidden"></div>
+
+            <div id="alert" style="visibility:hidden"></div>
+
+        <div class="lyricstable"><div id="lyricsmain" style="opacity:1" class="lyricscell lyricsmain"></div></div>
+        <div id="footer" class="footer"></div>
+        <div id="black" class="size"></div>
+        </body>
+        </html>
+"""
 import logging
 
 from PyQt4 import QtWebKit
@@ -114,12 +479,6 @@
         document.getElementById('black').style.display = black;
         document.getElementById('lyricsmain').style.visibility = lyrics;
         document.getElementById('image').style.visibility = lyrics;
-        outline = document.getElementById('lyricsoutline')
-        if(outline != null)
-            outline.style.visibility = lyrics;
-        shadow = document.getElementById('lyricsshadow')
-        if(shadow != null)
-            shadow.style.visibility = lyrics;
         document.getElementById('footer').style.visibility = lyrics;
     }
 
@@ -138,9 +497,6 @@
         */
         var txt = document.getElementById('lyricsmain');
         if(window.getComputedStyle(txt).textAlign == 'justify'){
-            var outline = document.getElementById('lyricsoutline');
-            if(outline != null)
-                txt = outline;
             if(window.getComputedStyle(txt).webkitTextStrokeWidth != '0px'){
                 new_text = new_text.replace(/(\s|&nbsp;)+(?![^<]*>)/g,
                     function(match) {
@@ -150,8 +506,6 @@
             }
         }
         text_fade('lyricsmain', new_text);
-        text_fade('lyricsoutline', new_text);
-        text_fade('lyricsshadow', new_text.replace(match, ''));
     }
 
     function text_fade(id, new_text){
@@ -190,7 +544,7 @@
 <img id="bgimage" class="size" %s />
 <img id="image" class="size" %s />
 %s
-%s
+<div class="lyricstable"><div id="lyricsmain" style="opacity:1" class="lyricscell lyricsmain"></div></div>
 <div id="footer" class="footer"></div>
 <div id="black" class="size"></div>
 </body>
@@ -222,8 +576,7 @@
     """
     width = screen['size'].width()
     height = screen['size'].height()
-    theme = item.themedata
-    webkit_ver = webkit_version()
+    theme_data = item.themedata
     # Image generated and poked in
     if background:
         bgimage_src = 'src="data:image/png;base64,%s"' % background
@@ -247,12 +600,12 @@
         build_background_css(item, width),
         css_additions,
         build_footer_css(item, height),
-        build_lyrics_css(item, webkit_ver),
-        'true' if theme and theme.display_slide_transition and is_live else 'false',
+        build_lyrics_css(item),
+        'true' if theme_data and theme_data.display_slide_transition and is_live else 'false',
         js_additions,
-        bgimage_src, image_src,
-        html_additions,
-        build_lyrics_html(item, webkit_ver)
+        bgimage_src,
+        image_src,
+        html_additions
     )
     return html
 
@@ -303,16 +656,13 @@
     return background
 
 
-def build_lyrics_css(item, webkit_ver):
+def build_lyrics_css(item):
     """
     Build the lyrics display css
 
     ``item``
         Service Item containing theme and location information
 
-    ``webkitvers``
-        The version of qtwebkit we're using
-
     """
     style = """
 .lyricstable {
@@ -328,81 +678,44 @@
     %s
 }
 .lyricsmain {
-%s
-}
-.lyricsoutline {
-%s
-}
-.lyricsshadow {
-%s
-}
-    """
-    theme = item.themedata
+    %s
+}
+"""
+    theme_data = item.themedata
     lyricstable = ''
     lyrics = ''
     lyricsmain = ''
-    outline = ''
-    shadow = ''
-    if theme and item.main:
+    if theme_data and item.main:
         lyricstable = 'left: %spx; top: %spx;' % (item.main.x(), item.main.y())
-        lyrics = build_lyrics_format_css(theme, item.main.width(), item.main.height())
-        # 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.
-        #
-        # Up to 534.3 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
-        #
-        # Up to 534.3 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 webkit_ver >= 533.3:
-            lyricsmain += build_lyrics_outline_css(theme)
-        else:
-            outline = build_lyrics_outline_css(theme)
-        if theme.font_main_shadow:
-            if theme.font_main_outline and webkit_ver <= 534.3:
-                shadow = 'padding-left: %spx; padding-top: %spx;' % \
-                    (int(theme.font_main_shadow_size) + (int(theme.font_main_outline_size) * 2),
-                    theme.font_main_shadow_size)
-                shadow += build_lyrics_outline_css(theme, True)
-            else:
-                lyricsmain += ' text-shadow: %s %spx %spx;' % \
-                    (theme.font_main_shadow_color, theme.font_main_shadow_size, theme.font_main_shadow_size)
-    lyrics_css = style % (lyricstable, lyrics, lyricsmain, outline, shadow)
+        lyrics = build_lyrics_format_css(theme_data, item.main.width(), item.main.height())
+        lyricsmain += build_lyrics_outline_css(theme_data)
+        if theme_data.font_main_shadow:
+            lyricsmain += ' text-shadow: %s %spx %spx;' % \
+                (theme_data.font_main_shadow_color, theme_data.font_main_shadow_size, theme_data.font_main_shadow_size)
+    lyrics_css = style % (lyricstable, lyrics, lyricsmain)
     return lyrics_css
 
 
-def build_lyrics_outline_css(theme, is_shadow=False):
+def build_lyrics_outline_css(theme_data):
     """
     Build the css which controls the theme outline. Also used by renderer for splitting verses
 
-    ``theme``
+    ``theme_data``
         Object containing theme information
-
-    ``is_shadow``
-        If true, use the shadow colors instead
     """
-    if theme.font_main_outline:
-        size = float(theme.font_main_outline_size) / 16
-        if is_shadow:
-            fill_color = theme.font_main_shadow_color
-            outline_color = theme.font_main_shadow_color
-        else:
-            fill_color = theme.font_main_color
-            outline_color = theme.font_main_outline_color
+    if theme_data.font_main_outline:
+        size = float(theme_data.font_main_outline_size) / 16
+        fill_color = theme_data.font_main_color
+        outline_color = theme_data.font_main_outline_color
         return ' -webkit-text-stroke: %sem %s; -webkit-text-fill-color: %s; ' % (size, outline_color, fill_color)
-    else:
-        return ''
-
-
-def build_lyrics_format_css(theme, width, height):
+    return ''
+
+
+def build_lyrics_format_css(theme_data, width, height):
     """
     Build the css which controls the theme format. Also used by renderer for splitting verses
 
-    ``theme``
+    ``theme_data``
         Object containing theme information
 
     ``width``
@@ -411,17 +724,17 @@
     ``height``
         Height of the lyrics block
     """
-    align = HorizontalType.Names[theme.display_horizontal_align]
-    valign = VerticalType.Names[theme.display_vertical_align]
-    if theme.font_main_outline:
-        left_margin = int(theme.font_main_outline_size) * 2
+    align = HorizontalType.Names[theme_data.display_horizontal_align]
+    valign = VerticalType.Names[theme_data.display_vertical_align]
+    if theme_data.font_main_outline:
+        left_margin = int(theme_data.font_main_outline_size) * 2
     else:
         left_margin = 0
     justify = 'white-space:pre-wrap;'
     # fix tag incompatibilities
-    if theme.display_horizontal_align == HorizontalType.Justify:
+    if theme_data.display_horizontal_align == HorizontalType.Justify:
         justify = ''
-    if theme.display_vertical_align == VerticalType.Bottom:
+    if theme_data.display_vertical_align == VerticalType.Bottom:
         padding_bottom = '0.5em'
     else:
         padding_bottom = '0'
@@ -429,41 +742,13 @@
         'text-align: %s; vertical-align: %s; font-family: %s; ' \
         'font-size: %spt; color: %s; line-height: %d%%; margin: 0;' \
         'padding: 0; padding-bottom: %s; padding-left: %spx; width: %spx; height: %spx; ' % \
-        (justify, align, valign, theme.font_main_name, theme.font_main_size,
-        theme.font_main_color, 100 + int(theme.font_main_line_adjustment), padding_bottom, left_margin, width, height)
-    if theme.font_main_outline:
-        if webkit_version() <= 534.3:
-            lyrics += ' letter-spacing: 1px;'
-    if theme.font_main_italics:
-        lyrics += ' font-style:italic; '
-    if theme.font_main_bold:
-        lyrics += ' font-weight:bold; '
-    return lyrics
-
-
-def build_lyrics_html(item, webkitvers):
-    """
-    Build the HTML required to show the lyrics
-
-    ``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 = ''
-    theme = item.themedata
-    if webkitvers <= 534.3 and theme and theme.font_main_outline:
-        lyrics += '<div class="lyricstable"><div id="lyricsshadow" style="opacity:1" ' \
-            'class="lyricscell lyricsshadow"></div></div>'
-        if webkitvers < 533.3:
-            lyrics += '<div class="lyricstable"><div id="lyricsoutline" style="opacity:1" ' \
-                'class="lyricscell lyricsoutline"></div></div>'
-    lyrics += '<div class="lyricstable"><div id="lyricsmain" style="opacity:1" ' \
-        'class="lyricscell lyricsmain"></div></div>'
+        (justify, align, valign, theme_data.font_main_name, theme_data.font_main_size,
+        theme_data.font_main_color, 100 + int(theme_data.font_main_line_adjustment), padding_bottom,
+        left_margin, width, height)
+    if theme_data.font_main_italics:
+        lyrics += 'font-style:italic; '
+    if theme_data.font_main_bold:
+        lyrics += 'font-weight:bold; '
     return lyrics
 
 

=== modified file 'openlp/core/ui/maindisplay.py'
--- openlp/core/ui/maindisplay.py	2013-08-31 18:17:38 +0000
+++ openlp/core/ui/maindisplay.py	2013-10-11 09:54:38 +0000
@@ -243,8 +243,6 @@
             # Windows if there are many items in the service to re-render.
             # Setting the div elements direct seems to solve the issue
             self.frame.findFirstElement("#lyricsmain").setInnerXml(slide)
-            self.frame.findFirstElement("#lyricsoutline").setInnerXml(slide)
-            self.frame.findFirstElement("#lyricsshadow").setInnerXml(slide)
 
     def alert(self, text, location):
         """

=== modified file 'openlp/core/ui/media/phononplayer.py'
--- openlp/core/ui/media/phononplayer.py	2013-08-31 18:17:38 +0000
+++ openlp/core/ui/media/phononplayer.py	2013-10-11 09:54:38 +0000
@@ -45,36 +45,22 @@
 log = logging.getLogger(__name__)
 
 ADDITIONAL_EXT = {
-        'audio/ac3': ['.ac3'],
-        'audio/flac': ['.flac'],
-        'audio/x-m4a': ['.m4a'],
-        'audio/midi': ['.mid', '.midi'],
-        'audio/x-mp3': ['.mp3'],
-        'audio/mpeg': ['.mp3', '.mp2', '.mpga', '.mpega', '.m4a'],
-        'audio/qcelp': ['.qcp'],
-        'audio/x-wma': ['.wma'],
-        'audio/x-ms-wma': ['.wma'],
-        'video/x-flv': ['.flv'],
-        'video/x-matroska': ['.mpv', '.mkv'],
-        'video/x-wmv': ['.wmv'],
-        'video/x-mpg': ['.mpg'],
-        'video/mpeg': ['.mp4', '.mts', '.mov'],
-        'video/x-ms-wmv': ['.wmv']}
-
-VIDEO_CSS = """
-#videobackboard {
-    z-index:3;
-    background-color: %(bgcolor)s;
-}
-#video1 {
-    background-color: %(bgcolor)s;
-    z-index:4;
-}
-#video2 {
-    background-color: %(bgcolor)s;
-    z-index:4;
-}
-"""
+    'audio/ac3': ['.ac3'],
+    'audio/flac': ['.flac'],
+    'audio/x-m4a': ['.m4a'],
+    'audio/midi': ['.mid', '.midi'],
+    'audio/x-mp3': ['.mp3'],
+    'audio/mpeg': ['.mp3', '.mp2', '.mpga', '.mpega', '.m4a'],
+    'audio/qcelp': ['.qcp'],
+    'audio/x-wma': ['.wma'],
+    'audio/x-ms-wma': ['.wma'],
+    'video/x-flv': ['.flv'],
+    'video/x-matroska': ['.mpv', '.mkv'],
+    'video/x-wmv': ['.wmv'],
+    'video/x-mpg': ['.mpg'],
+    'video/mpeg': ['.mp4', '.mts', '.mov'],
+    'video/x-ms-wmv': ['.wmv']
+}
 
 
 class PhononPlayer(MediaPlayer):
@@ -268,8 +254,7 @@
         """
         Add css style sheets to htmlbuilder
         """
-        background = QtGui.QColor(Settings().value('players/background color')).name()
-        return VIDEO_CSS % {'bgcolor': background}
+        return ''
 
     def get_info(self):
         """

=== added file 'tests/functional/openlp_core_lib/test_htmlbuilder.py'
--- tests/functional/openlp_core_lib/test_htmlbuilder.py	1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core_lib/test_htmlbuilder.py	2013-10-11 09:54:38 +0000
@@ -0,0 +1,324 @@
+"""
+Package to test the openlp.core.lib.htmlbuilder module.
+"""
+
+from unittest import TestCase
+from mock import MagicMock, patch
+
+from PyQt4 import QtCore
+
+from openlp.core.lib.htmlbuilder import build_html, build_background_css, build_lyrics_css, build_lyrics_outline_css, \
+    build_lyrics_format_css, build_footer_css
+from openlp.core.lib.theme import HorizontalType, VerticalType
+
+
+HTML = """
+<!DOCTYPE html>
+<html>
+<head>
+<title>OpenLP Display</title>
+<style>
+*{
+    margin: 0;
+    padding: 0;
+    border: 0;
+    overflow: hidden;
+    -webkit-user-select: none;
+}
+body {
+    ;
+}
+.size {
+    position: absolute;
+    left: 0px;
+    top: 0px;
+    width: 100%;
+    height: 100%;
+}
+#black {
+    z-index: 8;
+    background-color: black;
+    display: none;
+}
+#bgimage {
+    z-index: 1;
+}
+#image {
+    z-index: 2;
+}
+plugin CSS
+#footer {
+    position: absolute;
+    z-index: 6;
+    dummy: dummy;
+}
+/* lyric css */
+
+sup {
+    font-size: 0.6em;
+    vertical-align: top;
+    position: relative;
+    top: -0.3em;
+}
+</style>
+<script>
+    var timer = null;
+    var transition = false;
+    plugin JS
+
+    function show_image(src){
+        var img = document.getElementById('image');
+        img.src = src;
+        if(src == '')
+            img.style.display = 'none';
+        else
+            img.style.display = 'block';
+    }
+
+    function show_blank(state){
+        var black = 'none';
+        var lyrics = '';
+        switch(state){
+            case 'theme':
+                lyrics = 'hidden';
+                break;
+            case 'black':
+                black = 'block';
+                break;
+            case 'desktop':
+                break;
+        }
+        document.getElementById('black').style.display = black;
+        document.getElementById('lyricsmain').style.visibility = lyrics;
+        document.getElementById('image').style.visibility = lyrics;
+        document.getElementById('footer').style.visibility = lyrics;
+    }
+
+    function show_footer(footertext){
+        document.getElementById('footer').innerHTML = footertext;
+    }
+
+    function show_text(new_text){
+        var match = /-webkit-text-fill-color:[^;"]+/gi;
+        if(timer != null)
+            clearTimeout(timer);
+        /*
+        QtWebkit bug with outlines and justify causing outline alignment
+        problems. (Bug 859950) Surround each word with a <span> to workaround,
+        but only in this scenario.
+        */
+        var txt = document.getElementById('lyricsmain');
+        if(window.getComputedStyle(txt).textAlign == 'justify'){
+            if(window.getComputedStyle(txt).webkitTextStrokeWidth != '0px'){
+                new_text = new_text.replace(/(\s|&nbsp;)+(?![^<]*>)/g,
+                    function(match) {
+                        return '</span>' + match + '<span>';
+                    });
+                new_text = '<span>' + new_text + '</span>';
+            }
+        }
+        text_fade('lyricsmain', new_text);
+    }
+
+    function text_fade(id, new_text){
+        /*
+        Show the text.
+        */
+        var text = document.getElementById(id);
+        if(text == null) return;
+        if(!transition){
+            text.innerHTML = new_text;
+            return;
+        }
+        // Fade text out. 0.1 to minimize the time "nothing" is shown on the screen.
+        text.style.opacity = '0.1';
+        // Fade new text in after the old text has finished fading out.
+        timer = window.setTimeout(function(){_show_text(text, new_text)}, 400);
+    }
+
+    function _show_text(text, new_text) {
+        /*
+        Helper function to show the new_text delayed.
+        */
+        text.innerHTML = new_text;
+        text.style.opacity = '1';
+        // Wait until the text is completely visible. We want to save the timer id, to be able to call
+        // clearTimeout(timer) when the text has changed before finishing fading.
+        timer = window.setTimeout(function(){timer = null;}, 400);
+    }
+
+    function show_text_completed(){
+        return (timer == null);
+    }
+</script>
+</head>
+<body>
+<img id="bgimage" class="size" style="display:none;" />
+<img id="image" class="size" style="display:none;" />
+plugin HTML
+<div class="lyricstable"><div id="lyricsmain" style="opacity:1" class="lyricscell lyricsmain"></div></div>
+<div id="footer" class="footer"></div>
+<div id="black" class="size"></div>
+</body>
+</html>
+"""
+BACKGROUND_CSS_RADIAL = 'background: -webkit-gradient(radial, 5 50%, 100, 5 50%, 5, from(#000000), to(#FFFFFF)) fixed'
+LYRICS_CSS = """
+.lyricstable {
+    z-index: 5;
+    position: absolute;
+    display: table;
+    left: 10px; top: 20px;
+}
+.lyricscell {
+    display: table-cell;
+    word-wrap: break-word;
+    -webkit-transition: opacity 0.4s ease;
+    lyrics_format_css
+}
+.lyricsmain {
+     text-shadow: #000000 5px 5px;
+}
+"""
+LYRICS_OUTLINE_CSS = ' -webkit-text-stroke: 0.125em #000000; -webkit-text-fill-color: #FFFFFF; '
+LYRICS_FORMAT_CSS = ' word-wrap: break-word; text-align: justify; vertical-align: bottom; ' + \
+    'font-family: Arial; font-size: 40pt; color: #FFFFFF; line-height: 108%; margin: 0;padding: 0; ' + \
+    'padding-bottom: 0.5em; padding-left: 2px; width: 1580px; height: 810px; font-style:italic; font-weight:bold; '
+FOOTER_CSS = """
+    left: 10px;
+    bottom: 0px;
+    width: 1260px;
+    font-family: Arial;
+    font-size: 12pt;
+    color: #FFFFFF;
+    text-align: left;
+    white-space: nowrap;
+    """
+
+
+class Htmbuilder(TestCase):
+    def build_html_test(self):
+        """
+        Test the build_html() function
+        """
+        # GIVEN: Mocked arguments and function.
+        with patch('openlp.core.lib.htmlbuilder.build_background_css') as mocked_build_background_css, \
+                patch('openlp.core.lib.htmlbuilder.build_footer_css') as mocked_build_footer_css, \
+                patch('openlp.core.lib.htmlbuilder.build_lyrics_css') as mocked_build_lyrics_css:
+            # Mocked function.
+            mocked_build_background_css.return_value = ''
+            mocked_build_footer_css.return_value = 'dummy: dummy;'
+            mocked_build_lyrics_css.return_value = ''
+            # Mocked arguments.
+            item = MagicMock()
+            item.bg_image_bytes = None
+            screen = MagicMock()
+            is_live = False
+            background = None
+            plugin = MagicMock()
+            plugin.get_display_css = MagicMock(return_value='plugin CSS')
+            plugin.get_display_javascript = MagicMock(return_value='plugin JS')
+            plugin.get_display_html = MagicMock(return_value='plugin HTML')
+            plugins = [plugin]
+
+            # WHEN: Create the html.
+            html = build_html(item, screen, is_live, background, plugins=plugins)
+
+            # THEN: The returned html should match.
+            assert html == HTML
+
+    def build_background_css_radial_test(self):
+        """
+        Test the build_background_css() function with a radial background
+        """
+        # GIVEN: Mocked arguments.
+        item = MagicMock()
+        item.themedata.background_start_color = '#000000'
+        item.themedata.background_end_color = '#FFFFFF'
+        width = 10
+
+        # WHEN: Create the css.
+        css = build_background_css(item, width)
+
+        # THEN: The returned css should match.
+        assert BACKGROUND_CSS_RADIAL == css, 'The background css should be equal.'
+
+    def build_lyrics_css_test(self):
+        """
+        Test the build_lyrics_css() function
+        """
+        # GIVEN: Mocked method and arguments.
+        with patch('openlp.core.lib.htmlbuilder.build_lyrics_format_css') as mocked_build_lyrics_format_css, \
+                patch('openlp.core.lib.htmlbuilder.build_lyrics_outline_css') as mocked_build_lyrics_outline_css:
+            mocked_build_lyrics_format_css.return_value = 'lyrics_format_css'
+            mocked_build_lyrics_outline_css.return_value = ''
+            item = MagicMock()
+            item.main = QtCore.QRect(10, 20, 10, 20)
+            item.themedata.font_main_shadow = True
+            item.themedata.font_main_shadow_color = '#000000'
+            item.themedata.font_main_shadow_size = 5
+
+            # WHEN: Create the css.
+            css = build_lyrics_css(item)
+
+            # THEN: The css should be equal.
+            assert LYRICS_CSS == css, 'The lyrics css should be equal.'
+
+    def build_lyrics_outline_css_test(self):
+        """
+        Test the build_lyrics_outline_css() function
+        """
+        # GIVEN: The mocked theme data.
+        theme_data = MagicMock()
+        theme_data.font_main_outline = True
+        theme_data.font_main_outline_size = 2
+        theme_data.font_main_color = '#FFFFFF'
+        theme_data.font_main_outline_color = '#000000'
+
+        # WHEN: Create the css.
+        css = build_lyrics_outline_css(theme_data)
+
+        # THEN: The css should be equal.
+        assert LYRICS_OUTLINE_CSS == css, 'The outline css should be equal.'
+
+    def build_lyrics_format_css_test(self):
+        """
+        Test the build_lyrics_format_css() function
+        """
+        # GIVEN: Mocked arguments.
+        theme_data = MagicMock()
+        theme_data.display_horizontal_align = HorizontalType.Justify
+        theme_data.display_vertical_align = VerticalType.Bottom
+        theme_data.font_main_name = 'Arial'
+        theme_data.font_main_size = 40
+        theme_data.font_main_color = '#FFFFFF'
+        theme_data.font_main_italics = True
+        theme_data.font_main_bold = True
+        theme_data.font_main_line_adjustment = 8
+        width = 1580
+        height = 810
+
+        # WHEN: Get the css.
+        css = build_lyrics_format_css(theme_data, width, height)
+
+        # THEN: They should be equal.
+        assert LYRICS_FORMAT_CSS == css, 'The lyrics format css should be equal.'
+
+    def build_footer_css_test(self):
+       """
+       Test the build_footer_css() function
+       """
+       # GIVEN: Create a theme.
+       item = MagicMock()
+       item.footer = QtCore.QRect(10, 921, 1260, 103)
+       item.themedata.font_footer_name = 'Arial'
+       item.themedata.font_footer_size = 12
+       item.themedata.font_footer_color = '#FFFFFF'
+       height = 1024
+
+       # WHEN: create the css.
+       css = build_footer_css(item, height)
+
+       # THEN: THE css should be the same.
+       assert FOOTER_CSS == css, 'The footer strings should be equal.'
+

=== modified file 'tests/functional/openlp_core_lib/test_image_manager.py'
--- tests/functional/openlp_core_lib/test_image_manager.py	2013-09-19 21:02:28 +0000
+++ tests/functional/openlp_core_lib/test_image_manager.py	2013-10-11 09:54:38 +0000
@@ -30,8 +30,8 @@
 Package to test the openlp.core.ui package.
 """
 import os
+
 from unittest import TestCase
-
 from PyQt4 import QtGui
 
 from openlp.core.lib import Registry, ImageManager, ScreenList

=== modified file 'tests/functional/openlp_core_lib/test_serviceitem.py'
--- tests/functional/openlp_core_lib/test_serviceitem.py	2013-10-02 21:37:00 +0000
+++ tests/functional/openlp_core_lib/test_serviceitem.py	2013-10-11 09:54:38 +0000
@@ -32,10 +32,11 @@
 import os
 from unittest import TestCase
 
-from openlp.core.lib import ItemCapabilities, ServiceItem, Registry
+
 from tests.functional import MagicMock, patch
 from tests.utils import assert_length, convert_file_service_item
 
+
 VERSE = 'The Lord said to {r}Noah{/r}: \n'\
         'There\'s gonna be a {su}floody{/su}, {sb}floody{/sb}\n'\
         'The Lord said to {g}Noah{/g}:\n'\

=== modified file 'tests/functional/openlp_core_lib/test_settings.py'
--- tests/functional/openlp_core_lib/test_settings.py	2013-09-22 21:11:03 +0000
+++ tests/functional/openlp_core_lib/test_settings.py	2013-10-11 09:54:38 +0000
@@ -30,8 +30,10 @@
 Package to test the openlp.core.lib.settings package.
 """
 import os
+from tempfile import mkstemp
+
 from unittest import TestCase
-from tempfile import mkstemp
+from PyQt4 import QtGui
 
 from PyQt4 import QtGui
 


References