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