]> git.vomp.tv Git - vompclient.git/blob - surfacevector.cc
OSDOpenVG: Render on demand: Fix backing out of a view render race
[vompclient.git] / surfacevector.cc
1 /*
2     Copyright 2012 Marten Richter
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <wchar.h>
21 #include <stdlib.h>
22 #include <math.h>
23 #include "bitmap.h"
24 #include "staticartwork.h"
25 #include "surfacevector.h"
26
27 SurfaceVector::SurfaceVector(OsdVector* vosd)
28 {
29   osd = vosd;
30   commands.reserve(2048);
31 }
32
33 SurfaceVector::~SurfaceVector()
34 {
35
36   osd->removeSurface(this);
37
38   for (SVGCommand& command : commands)
39   {
40     osd->decrementDrawStyleHandleRefCount(command.getHandle()); // We remove the Style reference, so that osd can free stuff // FIXME BUG BUG BUG
41
42     ImageIndex ii = command.getImageIndex();
43     if (ii) osd->removeImageRef(ii);
44
45     LoadIndex li = command.getLoadIndex();
46     if (li) osd->removeLoadIndexRef(li);
47   }
48 }
49
50 int SurfaceVector::getFontHeight()
51 {
52   return (int)osd->getFontHeight();
53 }
54
55 float SurfaceVector::getCharWidth(wchar_t c)
56 {
57   return osd->getCharWidth(c);
58 }
59
60 /*
61  * By current design it's not permitted to have a surface without the first drawing being to
62  * fill with a background colour. The fillblt calls removeCommands which deletes all the old
63  * commands before the background colour becomes the new first command, then all the rest are
64  * redrawn on top. If you want to change this in future then do this as the first thing in
65  * Boxx::draw():
66  *   surface->clear();
67  * and have this function in here:
68  *   void SurfaceVector::clear()
69  *   {
70  *     removeCommands(0, 0, swidth, sheight);
71  *   }
72  * Or preferably a simpler one that doesn't do all the comparison work.
73 */
74
75 int SurfaceVector::drawText(const char* text, int x, int y, const DrawStyle& c)
76 {
77   return drawText(text, x, y, 0, c);
78 }
79
80 int SurfaceVector::drawText(const char* text, int x, int y, int width, const DrawStyle& c)
81 {
82   float shift = 0.;
83   const char* run = text;
84   size_t length = strlen(text);
85
86
87   command_mutex.lock();
88
89   VectorHandle ref;
90   float* charwidtharray = osd->getCharWidthArray();
91   int commands_size = commands.size();
92   int chars = 0;
93   commands.resize(commands_size + strlen(text));
94 #ifndef WIN32
95   mbstate_t state;
96   wchar_t tempo;
97   size_t num_bytes = 1;
98   memset((void*)&state, 0, sizeof(state));
99   num_bytes = mbrtowc(&tempo, run, length, &state);
100
101   while (num_bytes != ((size_t) -1) && num_bytes != ((size_t) -2) && length > 0)
102   {
103     ref = osd->getDrawStyleHandle(c); // Need to call this each time to have OSD get the ref count right. Maybe expose incRefCount sometime
104     SVGCommand::PaintGlyph(commands[commands_size + chars], x + shift, y, tempo, ref);
105     chars++;
106
107     float cur_shift = charwidtharray[tempo & 0xFF];
108
109     if (tempo && 0xFFFFFF00) cur_shift = osd->getCharWidth(tempo);
110
111     shift += cur_shift;
112     length -= num_bytes;
113     run += num_bytes;
114
115     if (shift > width && width > 0)
116     {
117       command_mutex.unlock();
118       return 1;
119     }
120
121     num_bytes = mbrtowc(&tempo, run, length, &state);
122   }
123
124 #else
125   wchar_t* temptext = new wchar_t[length + 1];
126   int real_length = MultiByteToWideChar(CP_UTF8, 0, text, -1,
127                                         temptext, length + 1) - 1;
128
129   for (int i = 0; i < real_length; i++)
130   {
131     ref = osd->getDrawStyleHandle(c); // Need to call this each time to have OSD get the ref count right. Maybe expose incRefCount sometime
132     SVGCommand::PaintGlyph(commands[commands_size + chars], x + shift, y, temptext[i], ref);
133     chars++;
134
135     float cur_shift = charwidtharray[temptext[i] & 0xFF];
136
137     if (temptext[i] && 0xFFFFFF00) cur_shift = osd->getCharWidth(temptext[i]);
138
139     shift += cur_shift;
140   }
141
142   delete[] temptext;
143 #endif
144
145   commands.resize(commands_size + chars);
146   command_mutex.unlock();
147   return 1;
148
149 }
150 int SurfaceVector::drawTextRJ(const char* text, int x, int y, const DrawStyle& c)
151 {
152   float shift = 0.;
153   const char* run = text;
154   size_t length = strlen(text);
155
156 #ifndef WIN32
157   mbstate_t state;
158   wchar_t tempo[1];
159   size_t num_bytes = 1;
160   memset((void*)&state, 0, sizeof(state));
161   num_bytes = mbrtowc(tempo, run, length, &state);
162
163   while (num_bytes != ((size_t) -1) && num_bytes != ((size_t) -2) && length > 0)
164   {
165     shift += osd->getCharWidth(*tempo);
166     length -= num_bytes;
167     run += num_bytes;
168     num_bytes = mbrtowc(tempo, run, length, &state);
169   }
170
171 #else
172   wchar_t* temptext = new wchar_t[length + 1];
173   int real_length = MultiByteToWideChar(CP_UTF8, 0, text, -1,
174                                         temptext, length + 1) - 1;
175
176   for (int i = 0; i < real_length; i++)
177   {
178     shift += osd->getCharWidth(temptext[i]);
179   }
180
181   delete[] temptext;
182 #endif
183   return drawText(text, (int)(x - shift), y, c);
184 }
185
186 int SurfaceVector::drawTextCentre(const char* text, int x, int y, const DrawStyle& c)
187 {
188   float shift = 0;
189   const char* run = text;
190   size_t length = strlen(text);
191
192 #ifndef WIN32
193   mbstate_t state;
194   wchar_t tempo[1];
195   size_t num_bytes = 1;
196   memset((void*)&state, 0, sizeof(state));
197   num_bytes = mbrtowc(tempo, run, length, &state);
198
199   while (num_bytes != ((size_t) -1) && num_bytes != ((size_t) -2) && length > 0)
200   {
201     shift += osd->getCharWidth(*tempo);
202     length -= num_bytes;
203     run += num_bytes;
204     num_bytes = mbrtowc(tempo, run, length, &state);
205   }
206
207 #else
208   wchar_t* temptext = new wchar_t[length + 1];
209   int real_length = MultiByteToWideChar(CP_UTF8, 0, text, -1,
210                                         temptext, length + 1) - 1;
211
212   for (int i = 0; i < real_length; i++)
213   {
214     shift += osd->getCharWidth(temptext[i]);
215   }
216
217   delete[] temptext;
218 #endif
219
220   return drawText(text, (int)(x - shift / 2.),  y, c);
221 }
222
223 void SurfaceVector::drawJpeg(const char* fileName, int x, int y, int* width, int* height)
224 {
225   StaticArtwork index = sa_MAX; // This is for compatibility only
226
227   if (strcmp(fileName, "/vdr.jpg") == 0)
228   {
229     index = sa_vdrlogo;
230     *height = 100; // this is faked so that the system does use the old coordinate system
231     *width = (int)ceil(190.f * osd->getPixelAspect());
232   }
233   else if (strcmp(fileName, "/wallpaperPAL.jpg") == 0)
234   {
235     index = sa_wallpaper;
236     *width = 720; // this is faked so that the system does use the old coordinate system
237     *height = 576;
238   }
239
240   if (index != sa_MAX)
241   {
242     TVMediaInfo info;
243     info.setStaticArtwork(index);
244     drawTVMedia(info, x, y, *width, *height, TopLeft);
245   }
246 }
247
248 /*
249 void SurfaceVector::drawJpeg(const char *fileName,int x, int y,int *width, int *height)
250 {
251         command_mutex.lock();
252         ImageIndex image=osd->getJpegRef(fileName,width,height);
253         commands.push_back(SVGCommand::PaintImage(x,y,*width,*height,image,0));
254         command_mutex.unlock();
255 }
256 */
257
258 void SurfaceVector::drawTVMedia(TVMediaInfo& tvmedia, float x, float y, float  width, float height, Corner corner)
259 {
260   command_mutex.lock();
261   ImageIndex image = 0;
262   LoadIndex load_index = osd->getTVMediaRef(tvmedia, image);
263
264   if (width != 0 && height != 0)
265   {
266     removeCommands(x, y, width, height);
267   }
268
269   if (image)
270   {
271     //Log::getInstance()->log("SurfaceVector", Log::DEBUG, "TVMedia Add instru image %d %d", load_index,image);
272     commands.push_back(SVGCommand::PaintImage(x, y, width, height, image, 0, corner));
273   }
274   else
275   {
276
277     commands.push_back(SVGCommand::PaintImageLoading(load_index, x, y, width, height, corner));
278     //Log::getInstance()->log("SurfaceVector", Log::DEBUG, "TVMedia Add instru image loading %d %d", load_index,image);
279   }
280
281   command_mutex.unlock();
282 }
283
284 void SurfaceVector::drawClippingRectangle(float x, float y, float w, float h)
285 {
286   command_mutex.lock();
287   commands.push_back(SVGCommand::PaintClipping((float)x, (float)y, (float)w, (float)h));
288   command_mutex.unlock();
289 }
290
291 int SurfaceVector::create(UINT width, UINT height)
292 {
293   sheight = height;
294   swidth = width;
295   return 1;
296 }
297 void SurfaceVector::display()
298 {
299   //nothing this is really mvp specific  // FIXME remove?
300 }
301
302 int SurfaceVector::fillblt(int x, int y, int width, int height, const DrawStyle& c)
303 {
304   command_mutex.lock();
305   removeCommands(x, y, width, height); // remove commands below the box
306   VectorHandle ref = osd->getDrawStyleHandle(c);
307   commands.push_back(SVGCommand::PaintPath(x, y, width, height, PIRectangle, ref));
308   command_mutex.unlock();
309   return 1;
310
311 }
312 void SurfaceVector::drawHorzLine(int x1, int x2, int y, const DrawStyle& c)
313 {
314   command_mutex.lock();
315   VectorHandle ref = osd->getDrawStyleHandle(c);
316   commands.push_back(SVGCommand::PaintPath(x1, y, x2 - x1, 1, PIHorzLine, ref));
317   command_mutex.unlock();
318 }
319
320 void SurfaceVector::drawVertLine(int x, int y1, int y2, const DrawStyle& c)
321 {
322   command_mutex.lock();
323   VectorHandle ref = osd->getDrawStyleHandle(c);
324   commands.push_back(SVGCommand::PaintPath(x, y1, 1, y2 - y1, PIVertLine, ref));
325   command_mutex.unlock();
326 }
327
328 void SurfaceVector::drawBitmap(int x, int y, const Bitmap& bm, const DisplayRegion& region)
329 {
330   //this is complicated
331   command_mutex.lock();
332   /*
333         unsigned int * data=(unsigned int*)malloc(sizeof(unsigned int)*bm.getWidth()*bm.getHeight());
334         for (UINT j = 0; j < bm.getHeight(); ++j){
335            for (UINT i = 0; i < bm.getWidth(); ++i)
336            {
337                    data[i+j*bm.getHeight()]=bm.getColour(i,j);
338            }
339       }*/
340   ImageIndex image = osd->getImagePalette(bm.getWidth(), bm.getHeight(), &(bm.rawData()[0]),
341                                           (const unsigned int*)&bm.palette.getColourVector()[0]); // data is freed by the OSD
342   //free(data);
343   float tx = x + region.windowx;
344   float ty = y + region.windowy;
345   float th = bm.getHeight();
346   float tw = bm.getWidth();
347
348   float scalex = 720.f / ((float) (region.framewidth + 1));
349   float scaley = 576.f / ((float) (region.frameheight + 1));
350   tx *= scalex;
351   ty *= scaley;
352   tw *= scalex;
353   th *= scaley;
354   SVGCommand temp = SVGCommand::PaintImage(tx, ty, tw, th, image, 0);
355   removeCommands(tx, ty, tw, th);
356   commands.push_back(temp);
357   command_mutex.unlock();
358 }
359
360 void SurfaceVector::drawPoint(int x, int y, DrawStyle& c, bool fastdraw)
361 {
362   if (!fastdraw) command_mutex.lock();
363
364   VectorHandle ref = osd->getDrawStyleHandle(c);
365   commands.push_back(SVGCommand::PaintPath(x, y, 1, 1, PIPoint, ref));
366
367   if (!fastdraw)  command_mutex.unlock();
368 }
369 void SurfaceVector::drawMonoBitmap(UCHAR* base, int dx, int dy, unsigned int height, unsigned int width, DrawStyle& nextColour)
370 {
371   command_mutex.lock();
372   ImageIndex image = osd->getMonoBitmapRef(base, width, height);
373   VectorHandle ref = osd->getDrawStyleHandle(nextColour);
374   removeCommands(dx, dy, width, height);
375   commands.push_back(SVGCommand::PaintImage(dx, dy, height, width, image, ref)); // FIXME BUG height and width wrong way around?
376   command_mutex.unlock();
377 }
378
379
380 int SurfaceVector::removeCommands(float x, float y, float width, float height)
381 {
382   // we iterate through all old commands in order to remove commands hidden by this rectangle
383   std::vector<SVGCommand>::iterator itty = commands.begin();
384   std::vector<SVGCommand>::iterator remstart;
385   bool remove = false;
386   float cx, cy, cw, ch;
387   cx = cy = 0.f;
388   cw = swidth;
389   ch = sheight;
390   bool clipping_erases = false;
391
392   while (itty != commands.end())
393   {
394     if ((clipping_erases // test if clipping helps
395          || (*itty).Test(x, y, width, height)  )
396         && (*itty).instr != DrawClipping)
397     {
398       //Log::getInstance()->log("OSD", Log::DEBUG, "Remove command %d %g %g %g %g %d %d",(*itty).instr,
399       //(*itty).x,(*itty).y,(*itty).w,(*itty).h,(*itty).handle,(*itty).target.image);
400       osd->decrementDrawStyleHandleRefCount((*itty).getHandle()); // We remove the Style reference, so that osd can free stuff // FIXME BUG BUG BUG
401       ImageIndex ii = (*itty).getImageIndex();
402
403       if (ii) osd->removeImageRef(ii);
404
405       LoadIndex li = (*itty).getLoadIndex();
406
407       if (li) osd->removeLoadIndexRef(li);
408
409       if (!remove)
410       {
411         remstart = itty;
412         remove = true;
413       }
414     }
415     else
416     {
417       if ((*itty).instr == DrawClipping)
418       {
419         if ((*itty).w == 0.f && (*itty).h == 0.f)
420         {
421           cx = cy = 0.f;
422           cw = swidth;
423           ch = sheight;
424
425         }
426         else
427         {
428           cx = (*itty).x;
429           cy = (*itty).y;
430           cw = (*itty).w;
431           ch = (*itty).h;
432         }
433
434         clipping_erases = (cx >= x) && (cy >= y) && ((cx + cw) <= (x + width)) && ((cy + ch) <= (y + height));
435       }
436
437       if (remove)
438       {
439         itty = commands.erase(remstart, itty);
440         remove = false;
441       }
442     }
443
444     itty++;
445   }
446
447   if (remove)
448   {
449     itty = commands.erase(remstart, itty);
450   }
451
452   return 1;
453
454 }
455
456 int SurfaceVector::updateToScreen(int sx, int sy, int w, int h, int dx, int dy)
457 {
458   // ok this method really works in a pixel oriented way
459   command_mutex.lock();
460   osd->updateOrAddSurface(this, dx - sx, dy - sy, swidth, sheight, commands);
461   command_mutex.unlock();
462   return 1;
463 }
464
465
466 /* This is for systems which need a locking of the drawing surface to speed up drawing */
467 void SurfaceVector::startFastDraw()
468 {
469   command_mutex.lock();
470 }
471 void SurfaceVector::endFastDraw()
472 {
473   command_mutex.unlock();
474 }
475
476
477 void SurfaceVector::drawTTChar(int ox, int oy, int x, int y, cTeletextChar c)
478 {
479   command_mutex.lock();
480   std::vector<SVGCommand>::iterator itty = commands.begin();
481
482   while (itty != commands.end())
483   {
484     if ((*itty).TTTest(ox, oy, x, y) )
485     {
486       itty = commands.erase(itty);
487       break;
488     }
489     else
490     {
491       itty++;
492     }
493   }
494
495   commands.push_back(SVGCommand::PaintTTchar(ox, oy, x, y, c.getInternal()));
496   command_mutex.unlock();
497 }