From 22106f6dd33097905c4d76f78a84661bd2c805d0 Mon Sep 17 00:00:00 2001
From: Klaus Schmidinger <vdr@tvdr.de>
Date: Wed, 11 Feb 2015 09:48:02 +0100
Subject: cOsd::RenderPixmaps() now returns a pointer to cPixmap instead of
 cPixmapMemory; a cPixmap with a negative layer no longer marks any portion of
 the OSD's view port as "dirty"; Added a missing initialization of "panning"
 to the constructor of cPixmapMemory

---
 CONTRIBUTORS |  2 ++
 HISTORY      | 16 +++++++++++++++-
 UPDATE-2.2.0 | 18 ++++++++++++++++++
 osd.c        | 62 ++++++++++++++++++++++++++++++++++++------------------------
 osd.h        | 14 +++++++++-----
 5 files changed, 81 insertions(+), 31 deletions(-)

diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 4ed73dfc..879c604a 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -3308,6 +3308,8 @@ Thomas Reufer <thomas@reufer.ch>
  for adding cOsdProvider::OsdSizeChanged()
  for suggesting to change the German translations if the texts related to "binary
  skipping"
+ for suggesting to change the return value of cOsd::RenderPixmaps() from cPixmapMemory
+ to cPixmap
 
 Eike Sauer <EikeSauer@t-online.de>
  for reporting a problem with channels that need more than 5 TS packets for detecting
diff --git a/HISTORY b/HISTORY
index f1af8eff..70acdc73 100644
--- a/HISTORY
+++ b/HISTORY
@@ -8523,7 +8523,7 @@ Video Disk Recorder Revision History
   copy process has been successful (problem reported by Christoph Haubrich).
 - Added the UPDATE-2.2.0 file.
 
-2015-02-10: Version 2.1.10
+2015-02-11: Version 2.1.10
 
 - Updated the Finnish OSD texts (thanks to Rolf Ahrenberg).
 - Updated the Macedonian OSD texts (thanks to Dimitar Petrovski).
@@ -8551,3 +8551,17 @@ Video Disk Recorder Revision History
   of using the environment variable VDR_CHARSET_OVERRIDE still works, but is now
   deprecated and may be removed in a future version. The value given in the --chartab
   option takes precedence over that in VDR_CHARSET_OVERRIDE.
+- cOsd::RenderPixmaps() now returns a pointer to cPixmap instead of cPixmapMemory
+  (suggested by Thomas Reufer). This is necessary to allow plugins with derived
+  cPixmap implementations to use this function. Plugins that use this function
+  with cPixmapMemory now need to add a dynamic cast to the call, as in
+
+    cPixmapMemory *pm = dynamic_cast<cPixmapMemory *>(RenderPixmaps()));
+
+  They also need to call DestroyPixmap(pm) instead of "delete pm" to properly release
+  the resulting pixmap after use.
+  The dvbhddevice plugin has been modified accordingly.
+- A cPixmap with a negative layer no longer marks any portion of the OSD's view port
+  as "dirty" when drawing on it. This may improve performance when drawing on a
+  hidden pixmap, because it avoids unnecessary refreshes of the OSD.
+- Added a missing initialization of "panning" to the constructor of cPixmapMemory.
diff --git a/UPDATE-2.2.0 b/UPDATE-2.2.0
index bb3058c8..566da1f5 100644
--- a/UPDATE-2.2.0
+++ b/UPDATE-2.2.0
@@ -127,6 +127,15 @@ Plugins:
 - Added cOsdProvider::OsdSizeChanged(), which plugins that implement an output device
   can call to signal a change in the OSD that requires a redraw of the currently
   displayed object.
+- cOsd::RenderPixmaps() now returns a pointer to cPixmap instead of cPixmapMemory
+  This is necessary to allow plugins with derived cPixmap implementations to use this
+  function. Plugins that use this function with cPixmapMemory now need to add
+  a dynamic cast to the call, as in
+
+    cPixmapMemory *pm = dynamic_cast<cPixmapMemory *>(RenderPixmaps()));
+
+  They also need to call DestroyPixmap(pm) instead of "delete pm" to properly release
+  the resulting pixmap after use.
 
 Skins:
 
@@ -220,6 +229,15 @@ OSD:
   is unexpected at this point. You can still navigate to
   the last replayed recording (if any) by pressing Ok repeatedly in the Recordings
   menu.
+- cOsd::RenderPixmaps() now returns a pointer to cPixmap instead of cPixmapMemory
+  This is necessary to allow plugins with derived cPixmap implementations to use this
+  function. Plugins that use this function with cPixmapMemory now need to add
+  a dynamic cast to the call, as in
+
+    cPixmapMemory *pm = dynamic_cast<cPixmapMemory *>(RenderPixmaps()));
+
+  They also need to call DestroyPixmap(pm) instead of "delete pm" to properly release
+  the resulting pixmap after use.
 
 Channels:
 
diff --git a/osd.c b/osd.c
index d31ee8a3..a475488e 100644
--- a/osd.c
+++ b/osd.c
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: osd.c 3.4 2015/01/15 11:20:56 kls Exp $
+ * $Id: osd.c 3.5 2015/02/11 09:48:02 kls Exp $
  */
 
 #include "osd.h"
@@ -984,12 +984,13 @@ cPixmap::cPixmap(int Layer, const cRect &ViewPort, const cRect &DrawPort)
 
 void cPixmap::MarkViewPortDirty(const cRect &Rect)
 {
-  dirtyViewPort.Combine(Rect.Intersected(viewPort));
+  if (layer >= 0)
+     dirtyViewPort.Combine(Rect.Intersected(viewPort));
 }
 
 void cPixmap::MarkViewPortDirty(const cPoint &Point)
 {
-  if (viewPort.Contains(Point))
+  if (layer >= 0 && viewPort.Contains(Point))
      dirtyViewPort.Combine(Point);
 }
 
@@ -1025,11 +1026,18 @@ void cPixmap::SetLayer(int Layer)
      esyslog("ERROR: pixmap layer %d limited to %d", Layer, MAXPIXMAPLAYERS - 1);
      Layer = MAXPIXMAPLAYERS - 1;
      }
-  if (Layer != layer) {
-     if (Layer > 0 || layer > 0)
-        MarkViewPortDirty(viewPort);
+  // The sequence here is important, because the view port is only marked as dirty
+  // if the layer is >= 0:
+  if (layer >= 0) {
+     MarkViewPortDirty(viewPort); // the pixmap is visible and may or may not become invisible
+     layer = Layer;
+     }
+  else if (Layer >= 0) {
      layer = Layer;
+     MarkViewPortDirty(viewPort); // the pixmap was invisible and has become visible
      }
+  else
+     layer = Layer; // the pixmap was invisible and remains so
   Unlock();
 }
 
@@ -1141,6 +1149,7 @@ cPixmapMemory::cPixmapMemory(int Layer, const cRect &ViewPort, const cRect &Draw
 :cPixmap(Layer, ViewPort, DrawPort)
 {
   data = MALLOC(tColor, this->DrawPort().Width() * this->DrawPort().Height());
+  panning = false;
 }
 
 cPixmapMemory::~cPixmapMemory()
@@ -1714,7 +1723,8 @@ void cOsd::DestroyPixmap(cPixmap *Pixmap)
      LOCK_PIXMAPS;
      for (int i = 1; i < pixmaps.Size(); i++) { // begin at 1 - don't let the background pixmap be destroyed!
          if (pixmaps[i] == Pixmap) {
-            pixmaps[0]->MarkViewPortDirty(Pixmap->ViewPort());
+            if (Pixmap->Layer() >= 0)
+               pixmaps[0]->MarkViewPortDirty(Pixmap->ViewPort());
             delete Pixmap;
             pixmaps[i] = NULL;
             return;
@@ -1737,9 +1747,9 @@ cPixmap *cOsd::AddPixmap(cPixmap *Pixmap)
   return Pixmap;
 }
 
-cPixmapMemory *cOsd::RenderPixmaps(void)
+cPixmap *cOsd::RenderPixmaps(void)
 {
-  cPixmapMemory *Pixmap = NULL;
+  cPixmap *Pixmap = NULL;
   if (isTrueColor) {
      LOCK_PIXMAPS;
      // Collect overlapping dirty rectangles:
@@ -1762,25 +1772,27 @@ cPixmapMemory *cOsd::RenderPixmaps(void)
         d.Combine(OldDirty);
         OldDirty = NewDirty;
 #endif
-        Pixmap = new cPixmapMemory(0, d);
-        Pixmap->Clear();
-        // Render the individual pixmaps into the resulting pixmap:
-        for (int Layer = 0; Layer < MAXPIXMAPLAYERS; Layer++) {
-            for (int i = 0; i < pixmaps.Size(); i++) {
-                if (cPixmap *pm = pixmaps[i]) {
-                   if (pm->Layer() == Layer)
-                   Pixmap->DrawPixmap(pm, d);
+        Pixmap = CreatePixmap(-1, d);
+        if (Pixmap) {
+           Pixmap->Clear();
+           // Render the individual pixmaps into the resulting pixmap:
+           for (int Layer = 0; Layer < MAXPIXMAPLAYERS; Layer++) {
+               for (int i = 0; i < pixmaps.Size(); i++) {
+                   if (cPixmap *pm = pixmaps[i]) {
+                      if (pm->Layer() == Layer)
+                         Pixmap->DrawPixmap(pm, d);
+                      }
                    }
-                }
-            }
+               }
 #ifdef DebugDirty
-        cPixmapMemory DirtyIndicator(7, NewDirty);
-        static tColor DirtyIndicatorColors[] = { 0x7FFFFF00, 0x7F00FFFF };
-        static int DirtyIndicatorIndex = 0;
-        DirtyIndicator.Fill(DirtyIndicatorColors[DirtyIndicatorIndex]);
-        DirtyIndicatorIndex = 1 - DirtyIndicatorIndex;
-        Pixmap->Render(&DirtyIndicator, DirtyIndicator.DrawPort(), DirtyIndicator.ViewPort().Point().Shifted(-Pixmap->ViewPort().Point()));
+           cPixmapMemory DirtyIndicator(7, NewDirty);
+           static tColor DirtyIndicatorColors[] = { 0x7FFFFF00, 0x7F00FFFF };
+           static int DirtyIndicatorIndex = 0;
+           DirtyIndicator.Fill(DirtyIndicatorColors[DirtyIndicatorIndex]);
+           DirtyIndicatorIndex = 1 - DirtyIndicatorIndex;
+           Pixmap->Render(&DirtyIndicator, DirtyIndicator.DrawPort(), DirtyIndicator.ViewPort().Point().Shifted(-Pixmap->ViewPort().Point()));
 #endif
+           }
         }
      }
   return Pixmap;
diff --git a/osd.h b/osd.h
index e5864c4f..9ef32ac7 100644
--- a/osd.h
+++ b/osd.h
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: osd.h 3.5 2015/01/15 11:23:52 kls Exp $
+ * $Id: osd.h 3.6 2015/02/11 09:48:02 kls Exp $
  */
 
 #ifndef __OSD_H
@@ -763,12 +763,13 @@ protected:
        ///< the pixmap could not be added to the list.
        ///< A derived class that implements its own cPixmap class must call AddPixmap()
        ///< in order to add a newly created pixmap to the OSD's list of pixmaps.
-  cPixmapMemory *RenderPixmaps(void);
+  cPixmap *RenderPixmaps(void);
        ///< Renders the dirty part of all pixmaps into a resulting pixmap that
        ///< shall be displayed on the OSD. The returned pixmap's view port is
        ///< set to the location of the rectangle on the OSD that needs to be
        ///< refreshed; its draw port's origin is at (0, 0), and it has the same
        ///< size as the view port.
+       ///< Only pixmaps with a non-negative layer value are rendered.
        ///< If there are several non-overlapping dirty rectangles from different pixmaps,
        ///< they are returned separately in order to avoid re-rendering large parts
        ///< of the OSD that haven't changed at all. The caller must therefore call
@@ -778,7 +779,7 @@ protected:
        ///< by putting a LOCK_PIXMAPS into the scope of the operation).
        ///< If there are no dirty pixmaps, or if this is not a true color OSD,
        ///< this function returns NULL.
-       ///< The caller must delete the returned pixmap after use.
+       ///< The caller must call DestroyPixmap() for the returned pixmap after use.
 public:
   virtual ~cOsd();
        ///< Shuts down the OSD.
@@ -930,13 +931,16 @@ public:
        ///< pixmaps, the Flush() function should basically do something like this:
        ///<
        ///<  LOCK_PIXMAPS;
-       ///<  while (cPixmapMemory *pm = RenderPixmaps()) {
+       ///<  while (cPixmapMemory *pm = dynamic_cast<cPixmapMemory *>(RenderPixmaps())) {
        ///<        int w = pm->ViewPort().Width();
        ///<        int h = pm->ViewPort().Height();
        ///<        int d = w * sizeof(tColor);
        ///<        MyOsdDrawPixmap(Left() + pm->ViewPort().X(), Top() + pm->ViewPort().Y(), pm->Data(), w, h, h * d);
-       ///<        delete pm;
+       ///<        DestroyPixmap(pm);
        ///<        }
+       ///<
+       ///< If a plugin uses a derived cPixmap implementation, it needs to use that
+       ///< type instead of cPixmapMemory.
   };
 
 #define MAXOSDIMAGES 64
-- 
cgit v1.2.3