← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~googol-hush/openlp/render into lp:openlp

 

Andreas Preikschat has proposed merging lp:~googol-hush/openlp/render into lp:openlp.

Requested reviews:
  Tim Bentley (trb143)

For more details, see:
https://code.launchpad.net/~googol-hush/openlp/render/+merge/62081

Hello,

New 'word by word' algorithm

This introduces a new algorithm for the "word by word" rendering. This algorithm has weaknesses and strengths (as well as the trunk implementation). It works like this:

Let us play a game. I think of a number between 1 and 100 and you have to figure out what number I am thinking of. The winner is the one who need fewer attempts. How do you proceed?

You: Is the number you are thinking of lower than 50?
Me: No, it is not.
You: Is the number lower than 75?
Me No, it is not.
You: Is the number lower than 87?
Me: Yes, it is.
You: Is the number lower than 81?
...
...

Basically that is what I have done here. I have some test data and a diagram for you (rendering Genesis 1 at different font sizes).

Diagram: http://ubuntuone.com/p/v7G/
Test Results: http://ubuntuone.com/p/v7N/

It is obvious that at 30px the average verse will fit on a slide (so we do not need to process "word by word"). The new algorithm is much better than trunk as long as the font size is below 130px.

Please, test it! The danger in rendering the text like this is, that it is less simple and an error in the algorithm can mean that it "eats" single words of a verse.
-- 
https://code.launchpad.net/~googol-hush/openlp/render/+merge/62081
Your team OpenLP Core is subscribed to branch lp:openlp.
=== modified file 'openlp/core/lib/renderer.py'
--- openlp/core/lib/renderer.py	2011-05-17 18:55:45 +0000
+++ openlp/core/lib/renderer.py	2011-05-24 07:21:14 +0000
@@ -335,7 +335,7 @@
             styled_text += styled_line
             html = self.page_shell + styled_text + HTML_END
             self.web.setHtml(html)
-            # Text too long so go to next page
+            # Text too long so go to next page.
             if self.web_frame.contentsSize().height() > self.page_height:
                 if force_page and line_count > 0:
                     Receiver.send_message(u'theme_line_count', line_count)
@@ -366,7 +366,7 @@
 
         """
         log.debug(u'_paginate_slide_words - Start')
-        line_end = u''
+        line_end = u' '
         if line_break:
             line_end = u'<br>'
         formatted = []
@@ -374,10 +374,11 @@
         previous_raw = u''
         lines = text.split(u'\n')
         for line in lines:
+            line = line.strip()
             styled_line = expand_tags(line)
             html = self.page_shell + previous_html + styled_line + HTML_END
             self.web.setHtml(html)
-            # Text too long so go to next page
+            # Text too long so go to next page.
             if self.web_frame.contentsSize().height() > self.page_height:
                 # Check if there was a verse before the current one and append
                 # it, when it fits on the page.
@@ -401,24 +402,56 @@
                             previous_html = styled_line + line_end
                             previous_raw = line + line_end
                             continue
-                words = self._words_split(line)
-                for word in words:
-                    styled_word = expand_tags(word)
-                    html = self.page_shell + previous_html + styled_word + \
-                        HTML_END
+                # Figure out how many words of the line will fit on screen by
+                # using the algorithm known as "binary chop".
+                raw_words = self._words_split(line)
+                html_words = [expand_tags(word) for word in raw_words]
+                smallest_index = 0
+                highest_index = len(html_words) - 1
+                index = int(highest_index / 2)
+                while True:
+                    html = self.page_shell + previous_html + \
+                        u''.join(html_words[:index + 1]).strip() + HTML_END
                     self.web.setHtml(html)
-                    # Text too long so go to next page
                     if self.web_frame.contentsSize().height() > \
                         self.page_height:
-                        while previous_raw.endswith(u'<br>'):
-                            previous_raw = previous_raw[:-4]
-                        formatted.append(previous_raw)
+                        # We know that it does not fit, so change/calculate the
+                        # new index and highest_index accordingly.
+                        highest_index = index
+                        index = int(index - (index - smallest_index) / 2)
+                    else:
+                        smallest_index = index
+                        index = int(index + (highest_index - index) / 2)
+                    # We found the number of words which will fit.
+                    if smallest_index == index or highest_index == index:
+                        index = smallest_index
+                        formatted.append(previous_raw.rstrip(u'<br>') +
+                            u''.join(raw_words[:index + 1]))
                         previous_html = u''
                         previous_raw = u''
-                    previous_html += styled_word
-                    previous_raw += word
-                previous_html += line_end
-                previous_raw += line_end
+                    else:
+                        continue
+                    # Check if the rest of the line fits on the slide. If it
+                    # does we do not have to do the much more intensive "word by
+                    # word" checking.
+                    html = self.page_shell + \
+                        u''.join(html_words[index + 1:]).strip() + HTML_END
+                    self.web.setHtml(html)
+                    if self.web_frame.contentsSize().height() <= \
+                        self.page_height:
+                        previous_html = \
+                            u''.join(html_words[index + 1:]).strip() + line_end
+                        previous_raw = \
+                            u''.join(raw_words[index + 1:]).strip() + line_end
+                        break
+                    else:
+                        # The other words do not fit, thus reset the indexes,
+                        # create a new list and continue with "word by word".
+                        raw_words = raw_words[index + 1:]
+                        html_words = html_words[index + 1:]
+                        smallest_index = 0
+                        highest_index = len(html_words) - 1
+                        index = int(highest_index / 2)
             else:
                 previous_html += styled_line + line_end
                 previous_raw += line + line_end


Follow ups