]> git.vomp.tv Git - vompclient.git/blob - osdopenvg.cc
Use system fonts
[vompclient.git] / osdopenvg.cc
1 /*
2     Copyright 2004-2005 Chris Tallon, 2006,2011-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, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21
22 #include "osdopenvg.h"
23 #include "mtd.h"
24 #include "videoomx.h"
25 #include "surface.h"
26 #include <Magick++.h>
27
28 #include "message.h"
29 #include "command.h"
30 #include "teletxt/txtfont.h"
31
32 #include <sys/syscall.h>
33 #include <fontconfig/fontconfig.h>
34 #include <vector>
35 #include <math.h>
36
37 using namespace Magick;
38
39 extern uint8_t vdr_data[]     asm("_binary_other_vdrhires_jpg_start");
40 extern uint8_t vdr_data_end[] asm("_binary_other_vdrhires_jpg_end");
41 extern uint8_t wallpaper_data[]     asm("_binary_other_wallpaper720p_jpg_start");
42 extern uint8_t wallpaper_data_end[] asm("_binary_other_wallpaper720p_jpg_end");
43
44
45 #define  BACKBUFFER_WIDTH 1280
46 #define  BACKBUFFER_HEIGHT 720
47
48
49 OsdOpenVG::OsdOpenVG()
50 {
51   vgmutex.Lock();
52   taskmutex.Lock();
53   lastrendertime=getTimeMS();
54   display_height=0;
55   display_width=0;
56   mode=0;
57   aspect_correction=1.;
58
59   freetype_inited=false;
60   wait_id=1;
61   const char *fontname="Droid Sans:style=Regular";
62   cur_fontname=(char*)malloc(strlen(fontname)+1);
63   strcpy(cur_fontname,fontname);
64
65 }
66
67 OsdOpenVG::~OsdOpenVG()
68 {
69
70   if (initted)
71   {
72                 shutdown();
73   }
74
75   if (cur_fontname) free(cur_fontname);
76   if (freetype_inited) FT_Done_Face(ft_face);
77   if (!fontnames.size()) {
78           vector<char*>::iterator itty=fontnames.begin();
79           while (itty!=fontnames.end()) {
80                   free((void*)*itty);
81
82                   itty++;
83           }
84   }
85   if (!fontnames_keys.size()) {
86           vector<char*>::iterator itty=fontnames_keys.begin();
87           while (itty!=fontnames_keys.end()) {
88                   free((void*)*itty);
89
90                   itty++;
91           }
92     }
93
94   vgmutex.Unlock();
95   taskmutex.Unlock();
96 }
97
98
99
100 int OsdOpenVG::init(void* device)
101 {
102   if (initted) return 0;
103   Video* video = Video::getInstance();
104    //window=*((HWND*)device);
105
106    // May be this device specific part should go to a device specific child class
107
108    //init broadcom chipset (Move to video?)
109
110
111    //First get connection to egl
112    egl_display=eglGetDisplay(EGL_DEFAULT_DISPLAY);
113
114    if (egl_display==EGL_NO_DISPLAY) {
115            Log::getInstance()->log("OSD", Log::WARN, "Could not get egl display! %x",eglGetError());
116            vgmutex.Unlock();
117            return 0;
118    }
119
120
121
122    if (eglInitialize(egl_display, NULL, NULL)==EGL_FALSE) {
123            Log::getInstance()->log("OSD", Log::WARN, "Initialising display failed! %x",eglGetError());
124            vgmutex.Unlock();
125            return 0;
126    }
127
128
129    const char *query_str=eglQueryString(egl_display,EGL_CLIENT_APIS);
130    if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
131    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",eglGetError());
132    query_str=eglQueryString(egl_display,EGL_EXTENSIONS);
133    if (query_str)    Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
134    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",eglGetError());
135
136    if (eglBindAPI(EGL_OPENVG_API)==EGL_FALSE) {
137            Log::getInstance()->log("OSD", Log::WARN, "Binding openvg api failed! %x",eglGetError());
138            vgmutex.Unlock();
139            return 0;
140    }
141
142    const EGLint attributs[]={
143                  EGL_RED_SIZE,8,EGL_GREEN_SIZE, 8,EGL_BLUE_SIZE, 8,EGL_ALPHA_SIZE, 8,
144          EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT,
145          EGL_CONFORMANT, EGL_OPENVG_BIT,
146          EGL_NONE
147    }; // Here, we might have to select the resolution!
148
149
150    EGLint number;
151
152    if (eglChooseConfig(egl_display, attributs, &egl_ourconfig, 1, &number)==EGL_FALSE) {
153            Log::getInstance()->log("OSD", Log::WARN, "Choosing egl config failed! %x",eglGetError());
154            vgmutex.Unlock();
155            return 0;
156    }
157
158
159
160    egl_context=eglCreateContext(egl_display,egl_ourconfig,NULL,NULL);
161    if (egl_context==EGL_NO_CONTEXT) {
162            Log::getInstance()->log("OSD", Log::WARN, "Creating egl context failed! %x",eglGetError());
163            vgmutex.Unlock();
164            return 0;
165    }
166
167    // warning broadcom specific, get display size!
168    display_width=display_height=0;
169    if (graphics_get_display_size(0, &display_width, &display_height)<0) {
170            Log::getInstance()->log("OSD", Log::WARN, "Getting display size failed! (BCM API) ");
171            vgmutex.Unlock();
172            return 0;
173    }
174    Log::getInstance()->log("OSD", Log::NOTICE, "Displaysize is %d x %d ",display_width, display_height);
175    VC_RECT_T dst_rect ={0,0,display_width,display_height};
176    VC_RECT_T src_rect={0,0,BACKBUFFER_WIDTH <<16,BACKBUFFER_HEIGHT<<16};
177   // VC_RECT_T src_rect_bg={0,0,1<<16,1<<16};
178  //  VC_RECT_T src_rect_im={0,0,1,1};
179
180   /* uint32_t back_image_ptr;
181    bcm_backres=vc_dispmanx_resource_create(VC_IMAGE_RGB888,1,1,&back_image_ptr);
182    unsigned int color=0x00FF0000;
183    vc_dispmanx_resource_write_data(bcm_backres,VC_IMAGE_RGB888,4,&color,&src_rect_im);*/
184
185    DISPMANX_UPDATE_HANDLE_T  bcm_update;
186    bcm_display=vc_dispmanx_display_open(0);
187    bcm_update=vc_dispmanx_update_start(0);
188    bcm_element=vc_dispmanx_element_add(bcm_update,bcm_display,
189          2,&dst_rect, 0,
190          &src_rect,DISPMANX_PROTECTION_NONE,0, 0, (DISPMANX_TRANSFORM_T) 0);
191
192
193  /*  bcm_background=vc_dispmanx_element_add(bcm_update,bcm_display,
194             0,&dst_rect,bcm_backres ,
195             &src_rect_bg,DISPMANX_PROTECTION_NONE,0, 0, (DISPMANX_TRANSFORM_T) 0);*/
196
197    vc_dispmanx_update_submit_sync(bcm_update);
198
199
200
201    static EGL_DISPMANX_WINDOW_T nativewindow;
202    nativewindow.element=bcm_element;
203    nativewindow.height=BACKBUFFER_HEIGHT;
204    nativewindow.width=BACKBUFFER_WIDTH;
205
206    egl_surface = eglCreateWindowSurface(egl_display,egl_ourconfig, &nativewindow,NULL );
207    if (egl_surface==EGL_NO_SURFACE) {
208            Log::getInstance()->log("OSD", Log::WARN, "Creating egl window surface failed!");
209            vgmutex.Unlock();
210            return 0;
211    }
212    Log::getInstance()->log("OSD", Log::DEBUG, "Making egl current in1%d",syscall(SYS_gettid));
213    if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {
214            Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed");
215            vgmutex.Unlock();
216                    return 0;
217    }
218    // Test stuff
219
220    query_str=(const char*)vgGetString(VG_VERSION) ;
221    if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
222    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",vgGetError());
223
224    query_str=(const char*)vgGetString(VG_VENDOR) ;
225    if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
226    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",vgGetError());
227
228    query_str=(const char*)vgGetString(VG_RENDERER) ;
229    if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
230    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",vgGetError());
231
232    query_str=(const char*)vgGetString(VG_EXTENSIONS) ;
233    if (query_str) Log::getInstance()->logLongString("OSD", Log::NOTICE, query_str);
234    else Log::getInstance()->log("OSD", Log::WARN, "Could not query display %x",vgGetError());
235
236   aspect_correction= ((float)BACKBUFFER_HEIGHT)/576.f/(((float)BACKBUFFER_WIDTH)/720.f);
237   initPaths();
238   if (!fontnames.size()) {
239           //inspired by and copied from vdr's code
240           FcInit();
241           FcObjectSet *objset= FcObjectSetBuild(FC_FAMILY, FC_STYLE, NULL);
242           FcPattern * pattern=FcPatternCreate();
243           FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
244           FcFontSet* fonts = FcFontList(NULL, pattern, objset);
245           for (int i=0; i<fonts->nfont;i++) {
246                   char *s = (char *)FcNameUnparse(fonts->fonts[i]);
247
248                   if (s) {
249                           char *c= strchr(s,':');
250                           if (c) {
251                                   char *s2= strchr(c+1,',');
252                                   if (s2) *s2=0;
253                           }
254                           char *p=strchr(s,',');
255                           if (p) {
256                                   if (!c) *p=0;
257                                   else memmove(p,c,strlen(c)+1);
258                           }
259                           char *key=(char*)malloc(strlen(s)+1);
260                           strcpy(key,s);
261                           fontnames_keys.push_back(key);
262                           char *s2=strstr(s,"style=");
263                           if (s2) {
264                                   memmove(s2,s2+6,strlen(s2+6)+1);
265                           }
266                           fontnames.push_back(s);
267                   }
268           }
269           FcFontSetDestroy(fonts);
270           FcPatternDestroy(pattern);
271           FcObjectSetDestroy(objset);
272   }
273
274   if (!loadFont(false)) {
275           return 0;
276   }
277   vgttfont=vgCreateFont(0);
278   vgttpaint=vgCreatePaint();
279   vgSetParameteri( vgttpaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
280   vgSetColor(vgttpaint,0xffffffff);
281
282   eglSwapInterval(egl_display, 1 );
283
284   Log::getInstance()->log("OSD", Log::DEBUG, "Making egl current out 1%d",syscall(SYS_gettid));
285   eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
286   //Now we will create the Screen
287   initted = 1; // must set this here or create surface won't work
288
289
290   /*if (((VideoOMX*)Video::getInstance())->initUsingOSDObjects()!=1) { //call Video for init  stuff
291           return 0;
292   }*/
293   InitializeMagick("");
294
295   pthread_cond_init(&vgtaskCond, NULL);
296   pthread_mutex_init(&vgtaskCondMutex, NULL);
297
298   threadStart();
299   taskmutex.Unlock();
300   vgmutex.Unlock();
301
302
303   return 1;
304 }
305
306
307 void OsdOpenVG::initPaths()
308 {
309
310
311         VGPath current;
312         current=vgCreatePath(VG_PATH_FORMAT_STANDARD,
313                         VG_PATH_DATATYPE_F,1.f,0.f,
314                         0,0,VG_PATH_CAPABILITY_ALL);
315
316         vguLine(current,0.f,0.f,1.f,0.f);
317         // HorzLine
318         std_paths[HorzLine]=current;
319
320         current=vgCreatePath(VG_PATH_FORMAT_STANDARD,
321                                 VG_PATH_DATATYPE_F,1.f,0.f,
322                                 0,0,VG_PATH_CAPABILITY_ALL);
323         vguLine(current,0.f,0.f,0.f,1.f);
324         // VertLine
325         std_paths[VertLine]=current;
326
327         current=vgCreatePath(VG_PATH_FORMAT_STANDARD,
328                                 VG_PATH_DATATYPE_F,1.f,0.f,
329                                 0,0,VG_PATH_CAPABILITY_ALL);
330         //vguRect(current,0.f,0.f,1.f,1.f);
331         vguRect(current,0.f,0.f,1.f,1.f);
332         // Rectabgle
333         std_paths[Rectangle]=current;
334
335         current=vgCreatePath(VG_PATH_FORMAT_STANDARD,
336                                 VG_PATH_DATATYPE_F,1.f,0.f,
337                                 0,0,0);
338         vguEllipse(current,0.f,0.f,1.f,1.f);
339         // Point
340         std_paths[Point]=current;
341
342 }
343
344 void OsdOpenVG::destroyPaths()
345 {
346         vgDestroyPath(std_paths[HorzLine]);
347         vgDestroyPath(std_paths[VertLine]);
348         vgDestroyPath(std_paths[Rectangle]);
349         vgDestroyPath(std_paths[Point]);
350
351 }
352
353 int OsdOpenVG::stopUpdate()
354 {
355         threadStop();
356         processTasks();
357         return 1;
358 }
359
360 void OsdOpenVG::purgeAllReferences()
361 {
362         images_ref.clear();
363         styles_ref.clear(); // remove all references
364
365
366         map<void *,ImageIndex>::iterator mitty=monobitmaps.begin();
367         while (mitty!=monobitmaps.end()) {
368                 vgDestroyImage((VGImage)(*mitty).second);
369                 mitty++;
370         }
371         monobitmaps.clear();
372
373         map<string,ImageIndex>::iterator jitty=jpegs.begin();
374         while (jitty!=jpegs.end()) {
375                 vgDestroyImage((VGImage)(*jitty).second);
376                 jitty++;
377         }
378         jpegs.clear();
379
380         map<pair<Colour*,unsigned int>,unsigned int>::iterator sitty=styles.begin();
381         while (sitty!=styles.end()) {
382                 vgDestroyPaint((VGPaint)(*sitty).second);
383                 sitty++;
384         }
385         styles.clear();
386
387 }
388
389 int OsdOpenVG::shutdown()
390 {
391   if (!initted) return 0;
392
393   initted = 0;
394   Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark1");
395   threadStop();
396   Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark1a");
397   //(((VideoOMX*)Video::getInstance())->shutdownUsingOSDObjects());
398   if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {
399           Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed in shutdown %x",eglGetError());
400   }
401   if (eglBindAPI(EGL_OPENVG_API)==EGL_FALSE) {
402           Log::getInstance()->log("OSD", Log::WARN, "Binding openvg api thread failed! %x",eglGetError());
403   }
404
405   Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark2");
406   processTasks();
407   Log::getInstance()->log("OSD", Log::DEBUG, "shutdown mark3");
408
409   taskmutex.Lock();
410   vgmutex.Lock();
411
412
413
414   //purgeAllReferences();
415
416   vgDestroyFont(vgfont);
417   vgDestroyFont(vgttfont);
418   vgDestroyPaint(vgttpaint);
419   destroyPaths();
420   float colclear[]={0.8f,0.8f,0.8f,1.f};
421   vgSetfv(VG_CLEAR_COLOR,4,colclear);
422   vgClear(0,0,BACKBUFFER_WIDTH,BACKBUFFER_HEIGHT);
423   eglSwapBuffers(egl_display, egl_surface);
424   Log::getInstance()->log("OSD", Log::DEBUG, "Making egl current out final");
425   eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
426   if (eglDestroySurface(egl_display,egl_surface)==EGL_FALSE) {
427           Log::getInstance()->log("OSD", Log::ERR, "eglDestroySurface failed %x",eglGetError());
428   }
429   if (eglDestroyContext(egl_display,egl_context)==EGL_FALSE) {
430           Log::getInstance()->log("OSD", Log::ERR, "eglDestroyContext failed %x",eglGetError());
431   }
432   if (eglTerminate(egl_display )==EGL_FALSE) {
433           Log::getInstance()->log("OSD", Log::ERR, "eglTerminate failed %x",eglGetError());
434   }
435
436   DISPMANX_UPDATE_HANDLE_T  bcm_update;
437   bcm_update=vc_dispmanx_update_start(0);
438
439   vc_dispmanx_element_remove(bcm_update,bcm_element);
440 //  vc_dispmanx_element_remove(bcm_update,bcm_background);
441   vc_dispmanx_update_submit_sync(bcm_update);
442 //  vc_dispmanx_resource_delete(bcm_backres);
443   vc_dispmanx_display_close(bcm_display);
444
445
446
447   return 1;
448 }
449
450
451
452
453 void OsdOpenVG::threadMethod()
454 {
455         // We have to claim the egl context for this thread
456         Log::getInstance()->log("OSD", Log::NOTICE, "Entering drawing thread");
457         if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)== EGL_FALSE) {
458                 Log::getInstance()->log("OSD", Log::WARN, "Making egl Current failed in thread %x",eglGetError());
459                 return;
460         }
461         if (eglBindAPI(EGL_OPENVG_API)==EGL_FALSE) {
462                 Log::getInstance()->log("OSD", Log::WARN, "Binding openvg api thread failed! %x",eglGetError());
463                 return;
464         }
465         int ts=0;
466         while (true)
467         {
468                 ts=1;
469                 unsigned int waittime=1;
470
471                 if (initted) {
472
473                         long long time1 = getTimeMS();
474                         if ((time1 - lastrendertime) > 200) {//5 fps for OSD updates are enough, avoids tearing
475                                 InternalRendering();
476                                 lastrendertime = getTimeMS();
477
478                         }
479                         if (processTasks()) ts=0;
480                 }
481                 if (!threadIsActive()) {
482                         if (eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT )== EGL_FALSE) {
483                                    Log::getInstance()->log("OSD", Log::WARN, "Making egl Current out thread failed");
484                         }
485                         threadCheckExit();
486                 }
487                 if (ts!=0) {
488                         struct timespec target_time;
489                         clock_gettime(CLOCK_REALTIME,&target_time);
490                         target_time.tv_nsec+=1000000LL*ts;
491                         if (target_time.tv_nsec>999999999) {
492                                 target_time.tv_nsec-=1000000000L;
493                                 target_time.tv_sec+=1;
494                         }
495                         threadLock();
496                         threadWaitForSignalTimed(&target_time);
497                         threadUnlock();
498                 }
499                 //Sleep(1);
500         }
501         eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
502 }
503
504
505 void OsdOpenVG::threadPostStopCleanup()
506 {
507         //Doing nothing
508         //goo;
509         Log::getInstance()->log("OSD", Log::NOTICE, "Exiting drawing thread");
510 }
511
512 void OsdOpenVG::InternalRendering(){
513         vgmutex.Lock();
514     float colclear[]={1.f,1.0f,1.f,1.f};
515     vgSetfv(VG_CLEAR_COLOR,4,colclear);
516         vgClear(0,0,BACKBUFFER_WIDTH,BACKBUFFER_HEIGHT);
517         vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
518
519
520         drawSurfaces(); //iterate through and draws all commands
521
522         //Show it to the user!
523         eglSwapBuffers(egl_display, egl_surface);
524         vgmutex.Unlock();
525
526 }
527
528 /*font stuff*/
529
530 float OsdOpenVG::getFontHeight()
531 {
532         return font_height; //dummy
533 }
534 float OsdOpenVG::getCharWidth(wchar_t c)
535 {
536         unsigned int glyph_index=FT_Get_Char_Index(ft_face,c);
537         return font_exp_x[glyph_index];
538 }
539
540 unsigned int OsdOpenVG::loadTTchar(cTeletextChar c)
541 {
542         unsigned int glyph_index=c.getGlyphIndex();
543         if (tt_font_chars.find(glyph_index)!=tt_font_chars.end())
544         {
545                 return glyph_index;
546         }
547
548         unsigned int buffer[10];
549         const VGfloat glyphOrigin[] = { 0.f, 0.f };
550         const VGfloat escapement[] = { 12.f, 0.f };
551         unsigned int * charmap = GetFontChar(c, buffer);
552         if (!charmap) { //invalid char
553                 return 0;
554         }
555         for (int i=0;i<10;i++) {
556                 buffer[i]=charmap[i]>>4;
557         }
558
559         VGImage handle = vgCreateImage(
560                         VG_A_8,
561                         12,
562                         10,
563                         VG_IMAGE_QUALITY_NONANTIALIASED | VG_IMAGE_QUALITY_FASTER
564                                         | VG_IMAGE_QUALITY_BETTER);
565         vgImageSubData(handle, buffer, 4, VG_A_1, 0, 0, 12, 10);
566         vgSetGlyphToImage(
567                         vgttfont,
568                         glyph_index,
569                         handle, glyphOrigin, escapement);
570         vgDestroyImage(handle);
571         tt_font_chars[glyph_index]=1;
572
573         return glyph_index;
574 }
575
576 int OsdOpenVG::getFontNames(const char *** names,const char *** names_keys)
577 {
578         *names=(const char**)&(fontnames[0]);
579         *names_keys=(const char**)&(fontnames_keys[0]);
580         return fontnames.size();
581 }
582
583 void OsdOpenVG::setFont(const char * fontname) {
584
585         if (strcmp(fontname,cur_fontname)) {
586                 // new font!
587                 if (cur_fontname) free(cur_fontname);
588                 cur_fontname=(char*)malloc(strlen(fontname)+1);
589                 strcpy(cur_fontname,fontname);
590
591                 struct OpenVGCommand comm;
592                 comm.task=OVGreplacefont;
593                 putOpenVGCommand(comm,false);
594
595
596         }
597 }
598
599
600 int  OsdOpenVG::loadFont(bool newfont)
601 {
602         int error;
603         float font_size=16.f;
604         if (!freetype_inited) {
605                 error=FT_Init_FreeType(&ft_library);
606                 if (error)
607                 {
608                         Log::getInstance()->log("OSD", Log::WARN, "Could not load freetype %x",error);
609                         return 0;
610                 }
611         }
612
613         if (!freetype_inited || newfont) {
614                 //first get the filename algorith extracted from vdr by Klaus Schmidinger
615                 FcInit();
616                 FcPattern *pattern=FcNameParse((FcChar8*)cur_fontname);
617                 FcPatternAddBool(pattern,FC_SCALABLE,FcTrue);
618                 FcConfigSubstitute(NULL,pattern,FcMatchPattern);
619                 FcDefaultSubstitute(pattern);
620                 FcResult fres;
621                 FcFontSet *fonts=FcFontSort(NULL,pattern,FcFalse,NULL,&fres);
622                 FcChar8 *filename=NULL;
623                 if (fonts) {
624                         for (int i=0;i<fonts->nfont;i++) {
625                                 FcBool canscale;
626                                 FcPatternGetBool(fonts->fonts[i],FC_SCALABLE,0,&canscale);
627                                 if (canscale){
628                                         FcPatternGetString(fonts->fonts[i],FC_FILE,0,&filename);
629                                         break;
630                                 }
631                         }
632                         FcFontSetDestroy(fonts);
633                 } else {
634                         Log::getInstance()->log("OSD", Log::CRIT, "Could not locate a font! Abort!");
635                         return 0;
636                 }
637                 FcPatternDestroy(pattern);
638
639                 Log::getInstance()->log("OSD", Log::NOTICE, "Load Font %s: %s", cur_fontname,filename);
640                 // second load the font
641                 FT_Face     new_ft_face;
642                 error=FT_New_Face(ft_library,(const char*)filename,0,&new_ft_face );
643                 if (error) {
644                         Log::getInstance()->log("OSD", Log::WARN, "Could not load font face %x %s",error,filename);
645                         return 0;
646                 }
647                 error=FT_Set_Char_Size(new_ft_face,0,font_size*256,0,0 /*dpi*/);
648                 if (error) {
649                         FT_Done_Face(new_ft_face);
650                         Log::getInstance()->log("OSD", Log::WARN, "Could not set  face size %x",error);
651                         return 0;
652                 }
653                 FT_Face old_ft_face=ft_face; // do it thread safe
654                 ft_face=new_ft_face;
655                 if (freetype_inited) FT_Done_Face(old_ft_face);//
656                 freetype_inited=true;
657         }
658         vgfont=vgCreateFont(0);
659         FT_ULong cur_char;
660         FT_UInt glyph;
661         font_height=ft_face->size->metrics.height/256.f;
662         cur_char = FT_Get_First_Char(ft_face,&glyph);
663         vector<VGubyte> segments;
664         vector<VGfloat> coord;
665         segments.reserve(256);
666         coord.reserve(1024);
667         //Log::getInstance()->log("OSD", Log::DEBUG, "Create Glyph test %d %x %x %d",cur_char,font_data_end,font_data,glyph);
668         while (glyph !=0)
669         {
670                 error=FT_Load_Glyph(ft_face,glyph,FT_LOAD_DEFAULT);
671                 if (error){
672                         FT_Done_Face(ft_face);
673                         Log::getInstance()->log("OSD", Log::WARN, "Could not load glyph %x",error);
674                         return 0;
675                 }
676                 VGPath path;
677                 FT_Outline ot=ft_face->glyph->outline;
678                 segments.clear();
679                 coord.clear();
680
681                 if (ot.n_contours ==0) {
682                         path=VG_INVALID_HANDLE;
683                 } else {
684                         path=vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
685                                         1.0f,0.f,0,0,VG_PATH_CAPABILITY_ALL);
686
687                         /* convert glyph */
688                         FT_Vector *pt=ot.points;
689                         const char *tags=ot.tags;
690                         const short* cont=ot.contours;
691                         short n_cont=ot.n_contours;
692                         short n_point=ot.n_points;
693                         short last_cont=0;
694                         for (short point=0;n_cont!=0;cont++,n_cont--) {
695                                 short next_cont=*cont+1;
696                                 bool first=true;
697                                 char last_tag=0;
698                                 short first_point=point;
699                                 //Log::getInstance()->log("OSD", Log::DEBUG, "runs %d",*cont);
700                                 for (;point<next_cont;point++) {
701                                         char tag=tags[point];
702                                         FT_Vector fpoint=pt[point];
703                                 //      Log::getInstance()->log("OSD", Log::DEBUG, "tag %d point %d %d: %d %d",tag,fpoint.x,fpoint.y,point,n_point);
704                                         if (first) {
705                                                 segments.push_back(VG_MOVE_TO);
706                                                 first=false;
707                                         } else if (tag &0x1) { //on curve
708                                                 if (last_tag &0x1) {
709                                                         segments.push_back(VG_LINE_TO);
710                                                 } else if (last_tag &0x2){
711                                                         segments.push_back(VG_CUBIC_TO);
712                                                 } else {
713                                                         segments.push_back(VG_QUAD_TO);
714                                                 }
715
716                                         } else {
717                                                 if (!(tag &0x2)){
718                                                         if (!(last_tag &0x1)) {
719                                                                 segments.push_back(VG_QUAD_TO);
720                                                                 int coord_size=coord.size();
721                                                                 VGfloat x=(coord[coord_size-2]+ ((float)fpoint.x)/256.f)*0.5f*aspect_correction;
722                                                                 VGfloat y=(coord[coord_size-1]+(font_size- ((float)fpoint.y)/256.f))*0.5f;
723                                                                 coord.push_back(x);
724                                                                 coord.push_back(y);
725                                                         }
726                                                 }
727
728
729                                         }
730                                         last_tag=tag;
731                                         coord.push_back(((float)fpoint.x)*aspect_correction/256.);
732                                         coord.push_back(font_size-((float)fpoint.y)/256.);
733                                         //Log::getInstance()->log("OSD", Log::DEBUG, "Create APD Glyph coord %d %d %g %g",fpoint.x,fpoint.y,coord[coord.size()-2],coord[coord.size()-1]);
734                                 }
735                                 if (!(last_tag &0x1)) {
736                                         if (last_tag &0x2) {
737                                                 segments.push_back(VG_CUBIC_TO);
738                                         } else {
739                                                 segments.push_back(VG_QUAD_TO);
740                                         }
741                                         coord.push_back(((float)pt[first_point].x)*aspect_correction/256.);
742                                         coord.push_back(font_size-((float)pt[first_point].y)/256.);
743                                 }
744                                 //segments.push_back(VG_CLOSE_PATH);
745
746
747                         }
748                         vgAppendPathData(path,segments.size(),&segments[0],&coord[0]);
749                         int n=0;
750                 /*      for (int m=0;m<segments.size();m++) {
751                                 switch (segments[m])
752                                 {
753                                 case VG_MOVE_TO:
754                                         Log::getInstance()->log("OSD", Log::DEBUG, "Move To %g %g",coord[n],coord[n+1]);n+=2; break;
755                                 case VG_LINE_TO:
756                                         Log::getInstance()->log("OSD", Log::DEBUG, "Line To %g %g",coord[n],coord[n+1]);n+=2; break;
757                                 case VG_CUBIC_TO:
758                                         Log::getInstance()->log("OSD", Log::DEBUG, "Cubic To %g %g %g %g %g %g",coord[n],coord[n+1],coord[n+2],coord[n+3],coord[n+4],coord[n+5]);n+=6; break;
759                                 case VG_QUAD_TO:
760                                         Log::getInstance()->log("OSD", Log::DEBUG, "Quad To %g %g %g %g",coord[n],coord[n+1],coord[n+2],coord[n+3]);n+=4; break;
761                                 case VG_CLOSE_PATH:
762                                         Log::getInstance()->log("OSD", Log::DEBUG, "Close Path"); break;
763                                 }
764
765                         }*/
766                         //vguRect(path,0.f,0.f,1.f,1.f);
767                         //Log::getInstance()->log("OSD", Log::DEBUG, "Create APD Glyph %d %x",segments.size(),vgGetError());
768                 }
769                 VGfloat ori[]={0.f,0.f};
770                 VGfloat esp[]={ft_face->glyph->advance.x/256.f*aspect_correction,ft_face->glyph->advance.y/256.f};
771                 font_exp_x[glyph]=ft_face->glyph->advance.x/256.f*aspect_correction; //recalculate
772
773                 vgSetGlyphToPath(vgfont,glyph,path,VG_FALSE,ori,esp);
774                 //Log::getInstance()->log("OSD", Log::DEBUG, "Create Glyph %d %d %x",path,glyph,vgGetError());
775                 if (path!=VG_INVALID_HANDLE) {
776                         vgDestroyPath(path);
777                 }
778                 cur_char = FT_Get_Next_Char(ft_face,cur_char,&glyph);
779         }
780         return 1;
781 }
782
783
784 void OsdOpenVG::drawSetTrans(SurfaceCommands & sc)
785 {
786         vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
787         vgLoadIdentity();
788         vgScale(((float)BACKBUFFER_WIDTH)/720.f, -((float)BACKBUFFER_HEIGHT)/576.f);
789         vgTranslate(0.f+sc.x,-576.f+sc.y);
790
791         vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
792         vgLoadIdentity();
793     vgScale(((float)BACKBUFFER_WIDTH)/720.f, -((float)BACKBUFFER_HEIGHT)/576.f);
794         vgTranslate(0.f+sc.x,-576.f+sc.y);
795
796         vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
797         vgLoadIdentity();
798         vgScale(((float)BACKBUFFER_WIDTH)/720.f, -((float)BACKBUFFER_HEIGHT)/576.f);
799         vgTranslate(0.f+sc.x,-576.f+sc.y);
800
801
802
803         //vgTranslate(0.f+sc.x,576.f-sc.y);
804         //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Translate %g %g",sc.x,sc.y);
805
806 }
807 void OsdOpenVG::executeDrawCommand(SVGCommand & command)
808 {
809
810         VGfloat  save_matrix[9];
811         switch (command.instr) {
812         case DrawPath: {
813         vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
814         //      VGuint rgba;
815         //      rgba = vgGetColor((VGPaint) command.reference);
816                 //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Path %d %x %g %g %g %g",command.reference,command.target.path_index,command.x,command.y,command.w,command.h);
817                 //vgSeti(VG_FILL_RULE,);
818
819                 vgGetMatrix(save_matrix);
820                 vgSetPaint((VGPaint) command.reference,VG_FILL_PATH);
821                 vgSetPaint((VGPaint) command.reference,VG_STROKE_PATH);
822                 vgTranslate(command.x,command.y);
823                 vgScale(command.w,command.h);
824                 vgDrawPath(std_paths[command.target.path_index],VG_FILL_PATH);
825                 vgLoadMatrix(save_matrix);
826         } break;
827         case DrawImage: {
828             vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
829                 vgGetMatrix(save_matrix);
830                 vgTranslate(command.x,command.y);
831                 //vgScale(command.w,command.h);
832                 if (command.reference) { //special behaviout for bw images they act as a mask on the current paint
833                         vgSetPaint((VGPaint) command.reference,VG_FILL_PATH);
834                         vgSetPaint((VGPaint) command.reference,VG_STROKE_PATH);
835                         vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_STENCIL);
836                         vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
837                         vgScale(aspect_correction,1.f);
838                 } else {
839                         VGfloat imagewidth=vgGetParameteri((VGImage) command.target.image, VG_IMAGE_WIDTH);
840                         VGfloat imageheight=vgGetParameteri((VGImage) command.target.image, VG_IMAGE_HEIGHT);
841                         //vgScale(720.f/((float)BACKBUFFER_WIDTH), 576.f/((float)BACKBUFFER_HEIGHT));
842                         float scalex=command.w/imagewidth;
843                         float scaley=command.h/imageheight;
844                         //vgScale(command.w/imagewidth,command.h/imageheight);
845                         vgScale(scalex,scaley);
846                         vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_NORMAL);
847                         //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Image Scale  %g %g %g %g %g %g",command.w,imagewidth,command.h,imageheight,scalex,scaley);
848                 }
849
850
851                 //vgLoadIdentity();
852                 //vgTranslate(200.f,500.f);
853                 //vgScale(100.f,100.f);
854
855                 vgDrawImage((VGImage) command.target.image);
856                 //Log::getInstance()->log("OSD", Log::DEBUG, "Draw Image %d %x %g %g %g %g %x",command.reference,command.target.image,command.x,command.y,command.w,command.h,
857                 //              vgGetError());
858                 if (command.reference) {
859                         vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_NORMAL);
860                         vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
861                 }
862                 vgLoadMatrix(save_matrix);
863         } break;
864         case DrawGlyph: {
865                 vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
866                 vgGetMatrix(save_matrix);
867                 vgSetPaint((VGPaint) command.reference,VG_FILL_PATH);
868                 vgSetPaint((VGPaint) command.reference,VG_STROKE_PATH);
869                 vgTranslate(command.x,command.y);
870                 VGfloat gori[]={0.,0.};
871                 vgSetfv(VG_GLYPH_ORIGIN,2,gori);
872
873                 unsigned int glyph_index=FT_Get_Char_Index(ft_face,command.target.textchar);
874                 vgDrawGlyph(vgfont,glyph_index,VG_FILL_PATH,VG_FALSE);
875                 //vgDrawPath(std_paths[Rectangle],VG_FILL_PATH);
876         /*      Log::getInstance()->log("OSD", Log::DEBUG, "Draw Glyph %d %c %d %g %g %x",command.reference,command.target.textchar,glyph_index,command.x,command.y,
877                                                 vgGetError());*/
878                 vgLoadMatrix(save_matrix);
879                 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
880         } break;
881         case DrawTTchar:{
882                 cTeletextChar tchar;
883                 tchar.setInternal(command.target.ttchar);
884                 vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
885                 vgGetMatrix(save_matrix);
886                 enumTeletextColor ttforegcolour=tchar.GetFGColor();
887                 enumTeletextColor ttbackgcolour=tchar.GetBGColor();
888             if (tchar.GetBoxedOut()) {
889                 ttforegcolour=ttcTransparent;
890                 ttbackgcolour=ttcTransparent;
891             }
892             vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_STENCIL);
893             vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
894
895
896                 vgTranslate(command.x+command.w*11.85f*1.4f,command.y+command.h*19.75f);
897                 VGfloat gori[]={0.,0.};
898                 vgSetfv(VG_GLYPH_ORIGIN,2,gori);
899
900                 vgScale(-1.4f,2.f);
901                 unsigned int color=Surface::enumTeletextColorToCoulour(ttbackgcolour).rgba();
902                 color=color<<8 | (color &0xff000000)>>24;
903                 vgSetColor(vgttpaint,color);
904                 vgSetPaint((VGPaint) vgttpaint,VG_FILL_PATH);
905                 vgSetPaint((VGPaint) vgttpaint,VG_STROKE_PATH);
906                 cTeletextChar filled;
907                 filled.setInternal(0x187f);
908                 unsigned int glyph_index=loadTTchar(filled);
909                 vgDrawGlyph(vgttfont,glyph_index,VG_FILL_PATH,VG_FALSE);
910
911                 color=Surface::enumTeletextColorToCoulour(ttforegcolour).rgba();
912                 color=color<<8 | (color &0xff000000)>>24;
913                 vgSetColor(vgttpaint,color);
914                 vgSetPaint((VGPaint) vgttpaint,VG_FILL_PATH);
915                 vgSetPaint((VGPaint) vgttpaint,VG_STROKE_PATH);
916                 glyph_index=loadTTchar(tchar);
917                 vgDrawGlyph(vgttfont,glyph_index,VG_FILL_PATH,VG_FALSE);
918
919                 /*      Log::getInstance()->log("OSD", Log::DEBUG, "Draw TTchar %x %x %x %x",glyph_index,ttforegcolour,Surface::enumTeletextColorToCoulour(ttforegcolour).rgba(),
920                                         vgGetColor(vgttpaint));*/
921
922
923                 vgLoadMatrix(save_matrix);
924                 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
925                 vgSeti(VG_IMAGE_MODE,VG_DRAW_IMAGE_NORMAL);
926                 vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
927
928         }break;
929         }
930 }
931
932 unsigned int OsdOpenVG::handleTask(OpenVGCommand& command)
933 {
934         switch (command.task){
935         case OVGreplacefont: {
936                  vgDestroyFont(vgfont);
937                  loadFont(true);
938                  return 0;
939         } break;
940
941         case OVGdestroyImageRef: {
942                 vgDestroyImage((VGImage)command.param1);
943                 return 0;
944         } break;
945         case OVGdestroyPaint: {
946                 Log::getInstance()->log("OSD", Log::DEBUG, "Draw Paint Destroy %d ",command.param1);
947                 vgDestroyPaint((VGPaint)command.param1);
948                 return 0;
949         } break;
950         case OVGcreateImagePalette: {
951                 VGImage input=vgCreateImage(VG_A_8,command.param1, command.param2,
952                                 VG_IMAGE_QUALITY_NONANTIALIASED|
953                                 VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER);
954                 vgImageSubData(input,command.data,command.param1,
955                                                         VG_A_8,0,0,command.param1, command.param2); // upload palettized image data
956                 VGImage handle=vgCreateImage(VG_sRGBA_8888,command.param1, command.param2,
957                                                 VG_IMAGE_QUALITY_NONANTIALIASED|
958                                                 VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER);
959                 VGuint *palette=(VGuint*)malloc(256*sizeof(VGuint));
960                 VGuint *in_palette=(VGuint*)command.data2;
961                 for (int i=0;i<256;i++) {
962                         VGuint color=in_palette[i];
963                         palette[i]=color<<8 | (color &0xff000000)>>24;
964                 }
965
966                 vgLookupSingle(handle,input,palette,VG_ALPHA,VG_FALSE,VG_FALSE);
967                 free(palette);
968                 vgDestroyImage(input);
969
970                 return handle;
971         } break;
972         case OVGcreateMonoBitmap: {
973                 VGImage handle=vgCreateImage(VG_A_1,command.param1, command.param2,
974                                         VG_IMAGE_QUALITY_NONANTIALIASED|
975                                         VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER);
976                 //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create mono  %d %d %x %d",command.param1,command.param2,vgGetError(),handle);
977                 unsigned int buffer_len=(command.param1*command.param2)>>3;
978                 unsigned char * buffer=(unsigned char*)malloc(buffer_len);
979                 unsigned char * r_buffer1=buffer;
980                 const unsigned char * r_buffer2=(const unsigned char *)command.data;
981                 unsigned char *buffer_end=buffer+buffer_len;
982                 while (r_buffer1!=buffer_end) {
983                         unsigned char byte=*r_buffer2;
984                         *r_buffer1=((byte * 0x0802LU & 0x22110LU) | (byte * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
985                         r_buffer1++;r_buffer2++;
986                 }
987
988
989                 vgImageSubData(handle,buffer,command.param1>>3,
990                                         VG_A_1,0,0,command.param1, command.param2);
991                 free(buffer);
992         //      Log::getInstance()->log("OSD", Log::DEBUG, "Draw create mono2  %d %d %x %d",command.param1,command.param2,vgGetError(),handle);
993                 return handle;
994         } break;
995         case OVGcreateImageFile: {
996                 VGImage handle;
997                 try{
998                         Image *imagefile=(Image*)command.data;
999                         Blob imageblob;
1000                         imagefile->write(&imageblob,"RGBA");
1001
1002
1003                         handle=vgCreateImage(VG_sXBGR_8888,imagefile->columns(),imagefile->rows(),
1004                                         VG_IMAGE_QUALITY_NONANTIALIASED|
1005                                         VG_IMAGE_QUALITY_FASTER|VG_IMAGE_QUALITY_BETTER);
1006                 //      Log::getInstance()->log("OSD", Log::DEBUG, "Draw create image details  %d %d %x mark1",imagefile->columns(),imagefile->rows(),*(unsigned int*)imageblob.data());
1007                         vgImageSubData(handle,imageblob.data(),imagefile->columns()*4,
1008                                         VG_sXBGR_8888,0,0,imagefile->columns(),imagefile->rows());
1009                 //      Log::getInstance()->log("OSD", Log::DEBUG, "Draw create image details  %d %d %x mark2",imagefile->columns(),imagefile->rows(),*(unsigned int*)imageblob.data());
1010                         delete imagefile;
1011                 }catch( Exception &error_ )
1012                 {
1013                         Log::getInstance()->log("OSD", Log::DEBUG, "Libmagick hT: %s",error_.what());
1014
1015                         return 0;
1016                 }
1017
1018                 //Log::getInstance()->log("OSD", Log::DEBUG, "Draw create file  %d %d %x %d",command.param1,command.param2,vgGetError(),handle);
1019                 return handle;
1020         } break;
1021         case OVGcreateColorRef :{
1022                 VGPaint handle;
1023                 handle=vgCreatePaint();
1024                 vgSetParameteri(handle, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
1025                 vgSetColor(handle,command.param1);
1026                 VGuint rgba;
1027                 rgba = vgGetColor((VGPaint)handle);
1028                 Log::getInstance()->log("OSD", Log::DEBUG, "Draw Paint %d %x %x",handle,command.param1,rgba);
1029                 return handle;
1030         } break;
1031         case OVGimageUploadLine: {
1032                 vgImageSubData((VGImage)command.param1,command.data,0,VG_sARGB_8888,0,command.param2,command.param3,1);
1033                 return 0;
1034         } break;
1035
1036         }
1037 }
1038
1039 bool OsdOpenVG::processTasks()
1040 {
1041         bool worked=false;
1042         taskmutex.Lock();
1043         vgmutex.Lock();
1044         while (vgcommands.size()>0)
1045         {
1046                 OpenVGCommand &comm=vgcommands.front();
1047                 OpenVGResponse resp;
1048                 resp.result=handleTask(comm);
1049                 resp.id=comm.id;
1050                 if (comm.id) {
1051                         vgresponses.push_back(resp);
1052                 }
1053                 vgcommands.pop_front();
1054                 taskmutex.Unlock();
1055                 vgmutex.Unlock();
1056                 //threadCheckExit();
1057                 pthread_mutex_lock(&vgtaskCondMutex);
1058                 pthread_cond_signal(&vgtaskCond);
1059                 pthread_mutex_unlock(&vgtaskCondMutex);
1060                 taskmutex.Lock();
1061                 vgmutex.Lock();
1062                 worked=true;
1063         }
1064         taskmutex.Unlock();
1065         vgmutex.Unlock();
1066
1067         return worked;
1068 }
1069
1070 bool OsdOpenVG::haveOpenVGResponse(unsigned int id,unsigned int * resp)
1071 {
1072         taskmutex.Lock();
1073         if (vgresponses.size()>0)
1074         {
1075                 deque<OpenVGResponse>::iterator itty=vgresponses.begin();
1076                 while (itty!=vgresponses.end())
1077                 {
1078                         if ((*itty).id==id) {
1079                                 *resp=(*itty).result;
1080                                 taskmutex.Unlock();
1081                                 return true;
1082                         }
1083                         itty++;
1084                 }
1085         }
1086         taskmutex.Unlock();
1087         return false;
1088 }
1089
1090
1091 unsigned int  OsdOpenVG::putOpenVGCommand(OpenVGCommand& comm,bool wait)
1092 {
1093         taskmutex.Lock();
1094         if (wait){
1095                 comm.id=wait_id;
1096                 wait_id++;
1097         } else {
1098                 comm.id=0; // we are not waiting
1099         }
1100         vgcommands.push_back(comm);
1101         taskmutex.Unlock();
1102         threadSignal();
1103         while (wait) {
1104                 unsigned int resp;
1105                 if (!haveOpenVGResponse(comm.id,&resp)) {
1106                         struct timespec target_time;
1107                         clock_gettime(CLOCK_REALTIME,&target_time);
1108                         target_time.tv_nsec+=1000000LL*100;
1109                         if (target_time.tv_nsec>999999999) {
1110                                         target_time.tv_nsec-=1000000000L;
1111                                         target_time.tv_sec+=1;
1112                         }
1113                         pthread_mutex_lock(&vgtaskCondMutex);
1114                         pthread_cond_timedwait(&vgtaskCond, &vgtaskCondMutex,&target_time);
1115                         pthread_mutex_unlock(&vgtaskCondMutex);
1116                 } else {
1117                         return resp;
1118                 }
1119         }
1120         return 0;
1121 }
1122
1123 void OsdOpenVG::imageUploadLine(ImageIndex index,unsigned int j,unsigned int width,void *data)
1124 {
1125         vgImageSubData((VGImage)index,data,0,VG_sARGB_8888,0,j,width,1);
1126
1127         struct OpenVGCommand comm;
1128         comm.task=OVGimageUploadLine;
1129         comm.param1=index;
1130         comm.param2=j;
1131         comm.param3=width;
1132         comm.data=data;
1133         putOpenVGCommand(comm,true);
1134 }
1135
1136 void OsdOpenVG::destroyImageRef(ImageIndex index)
1137 {
1138         struct OpenVGCommand comm;
1139         comm.task=OVGdestroyImageRef;
1140         comm.param1=index;
1141         putOpenVGCommand(comm,false);
1142 }
1143
1144 ImageIndex OsdOpenVG::createJpeg(const char* fileName, int *width,int *height)
1145 {
1146         Image* magicimage=NULL;
1147         bool mem=false;
1148         struct OpenVGCommand comm;
1149         comm.task=OVGcreateImageFile;
1150
1151         try{
1152                 // Now figure out, if it is a special case
1153                 if (strcmp(fileName,"/vdr.jpg")==0) {
1154                         magicimage=new Image(Blob(vdr_data,vdr_data_end-vdr_data));
1155                         *height=100; // this is faked so that the system does use the old coordinate system
1156                         *width=ceil(190.f*aspect_correction);
1157                         Log::getInstance()->log("OSD", Log::DEBUG, "LoadIm vdr.jpg");
1158                 } else if (strcmp(fileName,"/wallpaperPAL.jpg")==0) {
1159                         magicimage=new Image(Blob(wallpaper_data,wallpaper_data_end-wallpaper_data));
1160                         *width=720; // this is faked so that the system does use the old coordinate system
1161                         *height=576;
1162                         Log::getInstance()->log("OSD", Log::DEBUG, "LoadIm wallpaperPAL.jpg");
1163                 } else {
1164                         magicimage=new Image();
1165                         magicimage->read(fileName);
1166                         Log::getInstance()->log("OSD", Log::DEBUG, "LoadIm file: %s",fileName);
1167                         *width=ceil(magicimage->baseColumns()*aspect_correction); // this is faked so that the system does use the old coordinate system
1168                         *height=magicimage->baseRows();
1169                 }
1170
1171         }catch( Exception &error_ )
1172         {
1173                 Log::getInstance()->log("OSD", Log::DEBUG, "Libmagick: %s",error_.what());
1174
1175                 return 0;
1176         }
1177         comm.data=magicimage;
1178         return putOpenVGCommand(comm,true);
1179 }
1180
1181 ImageIndex OsdOpenVG::createMonoBitmap(void *base,int width,int height)
1182 {
1183         struct OpenVGCommand comm;
1184         comm.task=OVGcreateMonoBitmap;
1185         comm.param1=width;
1186         comm.param2=height;
1187         comm.data=base;
1188         return putOpenVGCommand(comm,true);
1189 }
1190
1191 ImageIndex OsdOpenVG::createImagePalette(int width,int height,const unsigned char *image_data,const unsigned int*palette_data)
1192 {
1193     struct OpenVGCommand comm;
1194     comm.task=OVGcreateImagePalette;
1195     comm.param1=width;
1196     comm.param2=height;
1197     comm.data=image_data;
1198     comm.data2=palette_data;
1199     return putOpenVGCommand(comm,true);
1200 }
1201
1202 void OsdOpenVG::destroyStyleRef(unsigned int index)
1203 {
1204         struct OpenVGCommand comm;
1205         comm.task=OVGdestroyPaint;
1206         comm.param1=index;
1207         putOpenVGCommand(comm,false);
1208 }
1209
1210 unsigned int OsdOpenVG::createStyleRef(const DrawStyle &c)
1211 {
1212         unsigned int col=c.rgba();
1213         struct OpenVGCommand comm;
1214         comm.task=OVGcreateColorRef;
1215         comm.param1=col<<8 | (col &0xff000000)>>24;
1216         comm.data=&c;
1217         return putOpenVGCommand(comm,true);
1218 }
1219
1220 unsigned int OsdOpenVG::createColorRef(const Colour &c)
1221 {
1222         unsigned int col=c.rgba();
1223         struct OpenVGCommand comm;
1224         comm.task=OVGcreateColorRef;
1225         comm.param1=col<<8 | (col &0xff000000)>>24;
1226         comm.data=&c;
1227         return putOpenVGCommand(comm,true);
1228 }
1229
1230