"Fossies" - the Fresh Open Source Software Archive

Member "navit-0.5.6/navit/graphics/qt5/graphics_qt5.cpp" (6 Mar 2021, 37883 Bytes) of package /linux/privat/navit-0.5.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "graphics_qt5.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.5.5_vs_0.5.6.

    1 /**
    2  * Navit, a modular navigation system.
    3  * Copyright (C) 2005-2017 Navit Team
    4  *
    5  * This program is free software; you can redistribute it and/or
    6  * modify it under the terms of the GNU General Public License
    7  * version 2 as published by the Free Software Foundation.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with this program; if not, write to the
   16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   17  * Boston, MA  02110-1301, USA.
   18  */
   19 
   20 #include <glib.h>
   21 #ifdef HAVE_UNISTD_H
   22 #include <unistd.h>
   23 #endif
   24 extern "C" {
   25 #include "config.h"
   26 #include "item.h" /* needs to be first, as attr.h depends on it */
   27 
   28 #include "callback.h"
   29 #include "color.h"
   30 #include "debug.h"
   31 #include "event.h"
   32 
   33 #include "point.h" /* needs to be before graphics.h */
   34 
   35 #include "graphics.h"
   36 #include "plugin.h"
   37 #include "window.h"
   38 }
   39 
   40 #include "event_qt5.h"
   41 #include "graphics_qt5.h"
   42 #include <QDBusConnection>
   43 #include <QDBusInterface>
   44 #include <QFile>
   45 #include <QFont>
   46 #include <QGuiApplication>
   47 #include <QPainter>
   48 #include <QPainterPath>
   49 #include <QPixmap>
   50 #include <QScreen>
   51 #include <QSvgRenderer>
   52 #if USE_QML
   53 #include "QNavitQuick.h"
   54 #include <QQmlApplicationEngine>
   55 #include <QQmlContext>
   56 #include <QQuickWindow>
   57 #endif
   58 #if USE_QWIDGET
   59 #include "QNavitWidget.h"
   60 #include <QApplication>
   61 #endif
   62 #if defined(WINDOWS) || defined(WIN32) || defined(HAVE_API_WIN32_CE)
   63 #include <windows.h>
   64 #endif
   65 
   66 #if USE_QML
   67 GraphicsPriv::GraphicsPriv(struct graphics_priv* gp) {
   68     this->gp = gp;
   69 }
   70 
   71 GraphicsPriv::~GraphicsPriv() {
   72 }
   73 
   74 void GraphicsPriv::emit_update() {
   75     emit update();
   76 }
   77 #endif
   78 
   79 QGuiApplication* navit_app = NULL;
   80 
   81 struct graphics_font_priv {
   82     QFont* font;
   83 };
   84 
   85 struct graphics_image_priv {
   86     QPixmap* pixmap;
   87 };
   88 
   89 static void graphics_destroy(struct graphics_priv* gr) {
   90 //        dbg(lvl_debug,"enter");
   91 #if HAVE_FREETYPE
   92     gr->freetype_methods.destroy();
   93 #endif
   94     /* destroy painter */
   95     if (gr->painter != NULL)
   96         delete (gr->painter);
   97     /* destroy pixmap */
   98     if (gr->pixmap != NULL)
   99         delete (gr->pixmap);
  100     /* destroy widget if root window*/
  101     if (gr->root) {
  102 #if USE_QWIDGET
  103         if (gr->widget != NULL)
  104             delete (gr->widget);
  105 #endif
  106 #if USE_QML
  107         if (gr->GPriv != NULL)
  108             delete (gr->GPriv);
  109 #endif
  110     }
  111     /* unregister from parent, if any */
  112     if (gr->parent != NULL) {
  113         g_hash_table_remove(gr->parent->overlays, gr);
  114     }
  115 #ifdef SAILFISH_OS
  116     if (gr->display_on_ev != NULL) {
  117         event_remove_timeout(gr->display_on_ev);
  118     }
  119     if (gr->display_on_cb != NULL) {
  120         g_free(gr->display_on_cb);
  121     }
  122 #endif
  123     /* destroy overlays hash */
  124     g_hash_table_destroy(gr->overlays);
  125     /* destroy global application if destroying the last */
  126     if (gr->root) {
  127         if (navit_app != NULL) {
  128             delete (navit_app);
  129         }
  130         navit_app = NULL;
  131         /* destroy argv if any */
  132         while (gr->argc > 0) {
  133             gr->argc--;
  134             if (gr->argv[gr->argc] != NULL)
  135                 g_free(gr->argv[gr->argc]);
  136         }
  137     }
  138     /* destroy self */
  139     g_free(gr);
  140 }
  141 
  142 static void font_destroy(struct graphics_font_priv* font) {
  143     //        dbg(lvl_debug,"enter");
  144     if (font->font != NULL)
  145         delete (font->font);
  146     g_free(font);
  147 }
  148 
  149 /**
  150  * @brief   font interface structure
  151  * This structure is preset with all function pointers provided by this implemention
  152  * to be returned as interface.
  153  */
  154 static struct graphics_font_methods font_methods = {
  155     font_destroy
  156 };
  157 
  158 /**
  159  * List of font families to use, in order of preference
  160  */
  161 static const char* fontfamilies[] = {
  162     "Liberation Sans",
  163     "Arial",
  164     "NcrBI4nh",
  165     "luximbi",
  166     "FreeSans",
  167     "DejaVu Sans",
  168     NULL,
  169 };
  170 
  171 /**
  172  * @brief   Allocate a font context
  173  * @param   gr  own private context
  174  * @param   meth    fill this structure with correct functions to be called with handle as interface to font
  175  * @param   font    font family e.g. "Arial"
  176  * @param   size    Font size in 16.6 fractional points @ 300dpi. This is bullsh***. The encoding is freetypes
  177  *          16.6 fixed point format usually giving points. One point is usually 72th part of an inch. But
  178  *          navit does not honor dpi correct. It's traditionally used freetype backend is fixed to 300 dpi.
  179  *          So this value is (300/72) pixels
  180  * @param   flags   Font flags (currently 1 if bold and 0 if not)
  181  *
  182  * @return  font handle
  183  *
  184  * Allocates a font handle and returnes filled interface stucture
  185  */
  186 static struct graphics_font_priv* font_new(struct graphics_priv* gr, struct graphics_font_methods* meth, char* font,
  187         int size, int flags) {
  188     int a = 0;
  189     struct graphics_font_priv* font_priv;
  190     dbg(lvl_debug, "enter (font %s, %d, 0x%x)", font, size, flags);
  191     font_priv = g_new0(struct graphics_font_priv, 1);
  192     font_priv->font = new QFont(fontfamilies[0]);
  193     if (font != NULL)
  194         font_priv->font->setFamily(font);
  195     /* search for exact font match */
  196     while ((!font_priv->font->exactMatch()) && (fontfamilies[a] != NULL)) {
  197         font_priv->font->setFamily(fontfamilies[a]);
  198         a++;
  199     }
  200     if (font_priv->font->exactMatch()) {
  201         dbg(lvl_debug, "Exactly matching font: %s", font_priv->font->family().toUtf8().data());
  202     } else {
  203         /* set any font*/
  204         if (font != NULL) {
  205             font_priv->font->setFamily(font);
  206         } else {
  207             font_priv->font->setFamily(fontfamilies[0]);
  208         }
  209         dbg(lvl_debug, "No matching font. Resort to: %s", font_priv->font->family().toUtf8().data());
  210     }
  211 
  212     /* Convert silly font size to pixels. by 64 is to convert fixpoint to int. */
  213     dbg(lvl_debug, "(font %s, %d=%f, %d)", font, size,((float)size)/64.0, ((size * 300) / 72) / 64);
  214     font_priv->font->setPixelSize(((size * 300) / 72) / 64);
  215     //font_priv->font->setStyleStrategy(QFont::NoSubpixelAntialias);
  216     /* Check for bold font */
  217     if (flags) {
  218         font_priv->font->setBold(true);
  219     }
  220 
  221     *meth = font_methods;
  222     return font_priv;
  223 }
  224 
  225 static void gc_destroy(struct graphics_gc_priv* gc) {
  226     //        dbg(lvl_debug,"enter gc=%p", gc);
  227     delete (gc->pen);
  228     delete (gc->brush);
  229     g_free(gc);
  230 }
  231 
  232 static void gc_set_linewidth(struct graphics_gc_priv* gc, int w) {
  233     //        dbg(lvl_debug,"enter gc=%p, %d", gc, w);
  234     gc->pen->setWidth(w);
  235 }
  236 
  237 static void gc_set_dashes(struct graphics_gc_priv* gc, int w, int offset, unsigned char* dash_list, int n) {
  238     if (n <= 0) {
  239         dbg(lvl_error, "Refuse to set dashes without dash pattern");
  240     }
  241     /* use Qt dash feature */
  242     QVector<qreal> dashes;
  243     gc->pen->setWidth(w);
  244     gc->pen->setDashOffset(offset);
  245     for (int a = 0; a < n; a++) {
  246         dashes << dash_list[a];
  247     }
  248     /* Qt requires the pattern to have even element count. Add the last
  249          * element twice if n doesn't divide by two
  250          */
  251     if ((n % 2) != 0) {
  252         dashes << dash_list[n - 1];
  253     }
  254     gc->pen->setDashPattern(dashes);
  255 }
  256 
  257 static void gc_set_foreground(struct graphics_gc_priv* gc, struct color* c) {
  258     QColor col(c->r >> 8, c->g >> 8, c->b >> 8, c->a >> 8);
  259     //        dbg(lvl_debug,"context %p: color %02x%02x%02x",gc, c->r >> 8, c->g >> 8, c->b >> 8);
  260     gc->pen->setColor(col);
  261     gc->brush->setColor(col);
  262     //gc->c=*c;
  263 }
  264 
  265 static void gc_set_background(struct graphics_gc_priv* gc, struct color* c) {
  266     QColor col(c->r >> 8, c->g >> 8, c->b >> 8, c->a >> 8);
  267     //        dbg(lvl_debug,"context %p: color %02x%02x%02x",gc, c->r >> 8, c->g >> 8, c->b >> 8);
  268     //gc->pen->setColor(col);
  269     //gc->brush->setColor(col);
  270 }
  271 
  272 void gc_set_texture (struct graphics_gc_priv *gc, struct graphics_image_priv *img) {
  273     if(img == NULL) {
  274         //disable texture mode
  275         gc->brush->setStyle(Qt::SolidPattern);
  276     } else {
  277         //set and enable texture
  278         //Use a new pixmap
  279         QPixmap background(img->pixmap->size());
  280         //Use fill color
  281         background.fill(gc->brush->color());
  282         //Get a painter
  283         QPainter painter(&background);
  284         //Blit the (transparent) image on pixmap.
  285         painter.drawPixmap(0, 0, *(img->pixmap));
  286         //Set the texture to the brush.
  287         gc->brush->setTexture(background);
  288     }
  289 }
  290 
  291 static struct graphics_gc_methods gc_methods = {
  292     gc_destroy,
  293     gc_set_linewidth,
  294     gc_set_dashes,
  295     gc_set_foreground,
  296     gc_set_background,
  297     gc_set_texture
  298 };
  299 
  300 static struct graphics_gc_priv* gc_new(struct graphics_priv* gr, struct graphics_gc_methods* meth) {
  301     struct graphics_gc_priv* graphics_gc_priv = NULL;
  302     //        dbg(lvl_debug,"enter gr==%p", gr);
  303     graphics_gc_priv = g_new0(struct graphics_gc_priv, 1);
  304     graphics_gc_priv->graphics_priv = gr;
  305     graphics_gc_priv->pen = new QPen();
  306     graphics_gc_priv->brush = new QBrush(Qt::SolidPattern);
  307 
  308     *meth = gc_methods;
  309     return graphics_gc_priv;
  310 }
  311 
  312 static void image_destroy(struct graphics_image_priv* img) {
  313     //    dbg(lvl_debug, "enter");
  314     if (img->pixmap != NULL)
  315         delete (img->pixmap);
  316     g_free(img);
  317 }
  318 
  319 struct graphics_image_methods image_methods = {
  320     image_destroy
  321 };
  322 
  323 static struct graphics_image_priv* image_new(struct graphics_priv* gr, struct graphics_image_methods* meth, char* path,
  324         int* w, int* h, struct point* hot, int rotation) {
  325     struct graphics_image_priv* image_priv;
  326     //        dbg(lvl_debug,"enter %s, %d %d", path, *w, *h);
  327     if (path[0] == 0) {
  328         dbg(lvl_debug, "Refuse to load image without path");
  329         return NULL;
  330     }
  331     QString key(path);
  332     QString renderer_key(key);
  333     int index = key.lastIndexOf(".");
  334     QString extension;
  335     if(index > 0) {
  336         extension = key.right(index);
  337     }
  338     QFile imagefile(key);
  339     if (!imagefile.exists()) {
  340         /* file doesn't exit. Either navit wants us to guess file name by
  341              * ommitting exstension, or the file does really not exist.
  342              */
  343         if (extension != "") {
  344             /*file doesn't exist. give up */
  345             dbg(lvl_debug, "File %s does not exist", path);
  346             return NULL;
  347         } else {
  348             /* add ".svg" for renderer to try .svg file first in renderer */
  349             dbg(lvl_debug, "Guess extension on %s", path);
  350             renderer_key += ".svg";
  351         }
  352     }
  353     image_priv = g_new0(struct graphics_image_priv, 1);
  354     *meth = image_methods;
  355 
  356     /* check if this can be rendered */
  357     if (renderer_key.endsWith("svg")) {
  358         QSvgRenderer renderer(renderer_key);
  359         if (renderer.isValid()) {
  360             dbg(lvl_debug, "render %s", path);
  361             /* try to render this */
  362             /* assume "standard" size if size is not given */
  363             if (*w <= 0)
  364                 *w = renderer.defaultSize().width();
  365             if (*h <= 0)
  366                 *h = renderer.defaultSize().height();
  367             image_priv->pixmap = new QPixmap(*w, *h);
  368             image_priv->pixmap->fill(Qt::transparent);
  369             QPainter painter(image_priv->pixmap);
  370             renderer.render(&painter);
  371         }
  372     }
  373 
  374     if (image_priv->pixmap == NULL) {
  375         /*cannot be rendered. try to load it */
  376         dbg(lvl_debug, "cannot render %s", path);
  377         image_priv->pixmap = new QPixmap(key);
  378     }
  379 
  380     /* check if we got image */
  381     if ((image_priv->pixmap == NULL) || (image_priv->pixmap->isNull())) {
  382         g_free(image_priv);
  383         return NULL;
  384     } else {
  385         /* check if we need to scale this */
  386         if ((*w > 0) && (*h > 0)) {
  387             if ((image_priv->pixmap->width() != *w) || (image_priv->pixmap->height() != *h)) {
  388                 dbg(lvl_debug, "scale pixmap %s, %d->%d,%d->%d", path, image_priv->pixmap->width(), *w, image_priv->pixmap->height(),
  389                     *h);
  390                 QPixmap* scaled = new QPixmap(image_priv->pixmap->scaled(*w, *h, Qt::IgnoreAspectRatio, Qt::FastTransformation));
  391                 delete (image_priv->pixmap);
  392                 image_priv->pixmap = scaled;
  393             }
  394         }
  395     }
  396 
  397     *w = image_priv->pixmap->width();
  398     *h = image_priv->pixmap->height();
  399     //        dbg(lvl_debug, "Got (%d,%d)", *w,*h);
  400     if (hot) {
  401         hot->x = *w / 2;
  402         hot->y = *h / 2;
  403     }
  404 
  405     return image_priv;
  406 }
  407 
  408 static void draw_lines(struct graphics_priv* gr, struct graphics_gc_priv* gc, struct point* p, int count) {
  409     int i;
  410     QPolygon polygon;
  411     //        dbg(lvl_debug,"enter gr=%p, gc=%p, (%d, %d)", gr, gc, p->x, p->y);
  412     if (gr->painter == NULL)
  413         return;
  414 
  415     for (i = 0; i < count; i++)
  416         polygon.putPoints(i, 1, p[i].x, p[i].y);
  417     gr->painter->setPen(*gc->pen);
  418     gr->painter->drawPolyline(polygon);
  419 }
  420 
  421 static void draw_polygon(struct graphics_priv* gr, struct graphics_gc_priv* gc, struct point* p, int count) {
  422     int i;
  423     QPolygon polygon;
  424     //        dbg(lvl_debug,"enter gr=%p, gc=%p, (%d, %d)", gr, gc, p->x, p->y);
  425     if (gr->painter == NULL)
  426         return;
  427 
  428     for (i = 0; i < count; i++)
  429         polygon.putPoints(i, 1, p[i].x, p[i].y);
  430     gr->painter->setPen(*gc->pen);
  431     gr->painter->setBrush(*gc->brush);
  432 
  433     gr->painter->drawPolygon(polygon);
  434 }
  435 
  436 static void draw_polygon_with_holes (struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count,
  437                                      int hole_count, int* ccount, struct point **holes) {
  438     int i;
  439     int j;
  440     QPainterPath path;
  441     QPainterPath inner;
  442     QPolygon polygon;
  443     //dbg(lvl_error,"enter gr=%p, gc=%p, (%d, %d) holes %d", gr, gc, p->x, p->y, hole_count);
  444     if (gr->painter == NULL)
  445         return;
  446     gr->painter->setPen(*gc->pen);
  447     gr->painter->setBrush(*gc->brush);
  448     /* construct outer polygon */
  449     for (i = 0; i < count; i++)
  450         polygon.putPoints(i, 1, p[i].x, p[i].y);
  451     /* add it to outer path */
  452     path.addPolygon(polygon);
  453     /* construct the polygons for the holes and add them to inner */
  454     for(j=0; j<hole_count; j ++) {
  455         QPolygon hole;
  456         for (i = 0; i < ccount[j]; i++)
  457             hole.putPoints(i, 1, holes[j][i].x, holes[j][i].y);
  458         inner.addPolygon(hole);
  459     }
  460     /* intersect */
  461     if(hole_count > 0)
  462         path = path.subtracted(inner);
  463 
  464     gr->painter->drawPath(path);
  465 }
  466 
  467 static void draw_rectangle(struct graphics_priv* gr, struct graphics_gc_priv* gc, struct point* p, int w, int h) {
  468     //  dbg(lvl_debug,"gr=%p gc=%p %d,%d,%d,%d", gr, gc, p->x, p->y, w, h);
  469     if (gr->painter == NULL)
  470         return;
  471     gr->painter->fillRect(p->x, p->y, w, h, *gc->brush);
  472 }
  473 
  474 static void draw_circle(struct graphics_priv* gr, struct graphics_gc_priv* gc, struct point* p, int r) {
  475     //        dbg(lvl_debug,"enter gr=%p, gc=%p, (%d,%d) r=%d", gr, gc, p->x, p->y, r);
  476     if (gr->painter == NULL)
  477         return;
  478     gr->painter->setPen(*gc->pen);
  479     gr->painter->drawArc(p->x - r / 2, p->y - r / 2, r, r, 0, 360 * 16);
  480 }
  481 
  482 /**
  483  * @brief   Render given text
  484  * @param   gr  own private context
  485  * @param   fg  foreground drawing context (for color)
  486  * @param   bg  background drawing context (for color)
  487  * @param   font    font context to use (allocated by font_new)
  488  * @param   text    String to calculate bbox for
  489  * @param   p   offset on gr context to place this text.
  490  * @param   dx  transformation matrix (16.16 fixpoint)
  491  * @param   dy  transformation matrix (16.16 fixpoint)
  492  *
  493  * Renders given text on gr surface. Draws nice contrast outline around text.
  494  */
  495 static void draw_text(struct graphics_priv* gr, struct graphics_gc_priv* fg, struct graphics_gc_priv* bg,
  496                       struct graphics_font_priv* font, char* text, struct point* p, int dx, int dy) {
  497     dbg(lvl_debug, "enter gc=%p, fg=%p, bg=%p pos(%d,%d) d(%d, %d) %s", gr, fg, bg, p->x, p->y, dx, dy, text);
  498     QPainter* painter = gr->painter;
  499     if (painter == NULL)
  500         return;
  501 #if HAVE_FREETYPE
  502     struct font_freetype_text* t;
  503     struct font_freetype_glyph *g, **gp;
  504     struct color transparent = { 0x0000, 0x0000, 0x0000, 0x0000 };
  505     struct color fgc;
  506     struct color bgc;
  507     QColor temp;
  508 
  509     int i, x, y;
  510 
  511     if (!font)
  512         return;
  513     /* extract colors */
  514     fgc.r = fg->pen->color().red() << 8;
  515     fgc.g = fg->pen->color().green() << 8;
  516     fgc.b = fg->pen->color().blue() << 8;
  517     fgc.a = fg->pen->color().alpha() << 8;
  518     if (bg != NULL) {
  519         bgc.r = bg->pen->color().red() << 8;
  520         bgc.g = bg->pen->color().green() << 8;
  521         bgc.b = bg->pen->color().blue() << 8;
  522         bgc.a = bg->pen->color().alpha() << 8;
  523     } else {
  524         bgc = transparent;
  525     }
  526 
  527     t = gr->freetype_methods.text_new(text, (struct font_freetype_font*)font, dx, dy);
  528     x = p->x << 6;
  529     y = p->y << 6;
  530     gp = t->glyph;
  531     i = t->glyph_count;
  532     if (bg) {
  533         while (i-- > 0) {
  534             g = *gp++;
  535             if (g->w && g->h) {
  536                 unsigned char* data;
  537                 QImage img(g->w + 2, g->h + 2, QImage::Format_ARGB32_Premultiplied);
  538                 data = img.bits();
  539                 gr->freetype_methods.get_shadow(g, (unsigned char*)data, img.bytesPerLine(), &bgc, &transparent);
  540 
  541                 painter->drawImage(((x + g->x) >> 6) - 1, ((y + g->y) >> 6) - 1, img);
  542             }
  543             x += g->dx;
  544             y += g->dy;
  545         }
  546     }
  547     x = p->x << 6;
  548     y = p->y << 6;
  549     gp = t->glyph;
  550     i = t->glyph_count;
  551     while (i-- > 0) {
  552         g = *gp++;
  553         if (g->w && g->h) {
  554             unsigned char* data;
  555             QImage img(g->w, g->h, QImage::Format_ARGB32_Premultiplied);
  556             data = img.bits();
  557             gr->freetype_methods.get_glyph(g, (unsigned char*)data, img.bytesPerLine(), &fgc, &bgc, &transparent);
  558             painter->drawImage((x + g->x) >> 6, (y + g->y) >> 6, img);
  559         }
  560         x += g->dx;
  561         y += g->dy;
  562     }
  563     gr->freetype_methods.text_destroy(t);
  564 #else
  565     QString tmp = QString::fromUtf8(text);
  566     qreal m_dx = ((qreal)dx) / 65536.0;
  567     qreal m_dy = ((qreal)dy) / 65536.0;
  568     QMatrix sav = painter->worldMatrix();
  569     QMatrix m(m_dx, m_dy, -m_dy, m_dx, p->x, p->y);
  570     painter->setWorldMatrix(m, TRUE);
  571     painter->setFont(*font->font);
  572     if (bg) {
  573         QPen shadow;
  574         QPainterPath path;
  575         shadow.setColor(bg->pen->color());
  576         shadow.setWidth(3);
  577         painter->setPen(shadow);
  578         path.addText(0, 0, *font->font, tmp);
  579         painter->drawPath(path);
  580     }
  581     painter->setPen(*fg->pen);
  582     painter->drawText(0, 0, tmp);
  583     painter->setWorldMatrix(sav);
  584 #endif
  585 }
  586 
  587 static void draw_image(struct graphics_priv* gr, struct graphics_gc_priv* fg, struct point* p,
  588                        struct graphics_image_priv* img) {
  589     //        dbg(lvl_debug,"enter");
  590     if (gr->painter != NULL)
  591         gr->painter->drawPixmap(p->x, p->y, *img->pixmap);
  592     else
  593         dbg(lvl_debug, "Try to draw image, but no painter");
  594 }
  595 
  596 /**
  597  * @brief   Drag layer.
  598  * @param   gr private handle
  599  * @param   p   vector the bitmap is moved from base, or NULL to indicate 0:0 vector
  600  *
  601  * Move layer to new position. If drag_bitmap is enabled this may also be
  602  * called for root layer. There the content of the root layer is to be moved
  603  * by given vector. On root layer, NULL indicates the end of a drag.
  604  */
  605 static void draw_drag(struct graphics_priv* gr, struct point* p) {
  606     struct point vector;
  607 
  608     if (p != NULL) {
  609         dbg(lvl_debug, "enter %p (%d,%d)", gr, p->x, p->y);
  610         vector = *p;
  611     } else {
  612         dbg(lvl_debug, "enter %p (NULL)", gr);
  613         vector.x = 0;
  614         vector.y = 0;
  615     }
  616     if (gr->root) {
  617         gr->scroll_x = vector.x;
  618         gr->scroll_y = vector.y;
  619     } else {
  620 #if USE_QWIDGET
  621         int damage_x = gr->x;
  622         int damage_y = gr->y;
  623         int damage_w = gr->pixmap->width();
  624         int damage_h = gr->pixmap->height();
  625 #endif
  626         gr->x = vector.x;
  627         gr->y = vector.y;
  628 #if USE_QWIDGET
  629         /* call repaint on widget for stale area. */
  630         if (gr->widget != NULL)
  631             gr->widget->repaint(damage_x, damage_y, damage_w, damage_h);
  632 #endif
  633 #if USE_QML
  634 // No need to emit update, as QNavitQuic always repaints everything.
  635 //    if (gr->GPriv != NULL)
  636 //        gr->GPriv->emit_update();
  637 #endif
  638     }
  639 }
  640 
  641 static void background_gc(struct graphics_priv* gr, struct graphics_gc_priv* gc) {
  642     //        dbg(lvl_debug,"register context %p on %p", gc, gr);
  643     gr->background_graphics_gc_priv = gc;
  644 }
  645 
  646 static void draw_mode(struct graphics_priv* gr, enum draw_mode_num mode) {
  647     switch (mode) {
  648     case draw_mode_begin:
  649         dbg(lvl_debug, "Begin drawing on context %p (use == %d)", gr, gr->use_count);
  650         gr->use_count++;
  651         if (gr->painter == NULL) {
  652             if(gr->parent != NULL)
  653                 gr->pixmap->fill(QColor(0,0,0,0));
  654             gr->painter = new QPainter(gr->pixmap);
  655         } else
  656             dbg(lvl_debug, "drawing on %p already active", gr);
  657         break;
  658     case draw_mode_end:
  659         dbg(lvl_debug, "End drawing on context %p (use == %d)", gr, gr->use_count);
  660         gr->use_count--;
  661         if (gr->use_count < 0)
  662             gr->use_count = 0;
  663         if (gr->use_count > 0) {
  664             dbg(lvl_debug, "drawing on %p still in use", gr);
  665         } else if (gr->painter != NULL) {
  666             gr->painter->end();
  667             delete (gr->painter);
  668             gr->painter = NULL;
  669         } else {
  670             dbg(lvl_debug, "Context %p not active!", gr)
  671         }
  672 #if USE_QWIDGET
  673         /* call repaint on widget */
  674         if (gr->widget != NULL)
  675             gr->widget->repaint(gr->x, gr->y, gr->pixmap->width(), gr->pixmap->height());
  676 #endif
  677 #if USE_QML
  678         if (gr->GPriv != NULL)
  679             gr->GPriv->emit_update();
  680 
  681 #endif
  682 
  683         break;
  684     default:
  685         dbg(lvl_debug, "Unknown drawing %d on context %p", mode, gr);
  686         break;
  687     }
  688 }
  689 
  690 static struct graphics_priv* overlay_new(struct graphics_priv* gr, struct graphics_methods* meth, struct point* p,
  691         int w, int h, int wraparound);
  692 
  693 void resize_callback(struct graphics_priv* gr, int w, int h) {
  694     //        dbg(lvl_debug,"enter (%d, %d)", w, h);
  695     callback_list_call_attr_2(gr->callbacks, attr_resize, GINT_TO_POINTER(w), GINT_TO_POINTER(h));
  696 }
  697 
  698 static int graphics_qt5_fullscreen(struct window* w, int on) {
  699     struct graphics_priv* gr;
  700     //        dbg(lvl_debug,"enter");
  701     gr = (struct graphics_priv*)w->priv;
  702 #if USE_QML
  703     if (gr->window != NULL) {
  704         if (on)
  705             gr->window->setWindowState(Qt::WindowFullScreen);
  706         else
  707             gr->window->setWindowState(Qt::WindowMaximized);
  708     }
  709 #endif
  710 #if USE_QWIDGET
  711     if (gr->widget != NULL) {
  712         if (on)
  713             gr->widget->setWindowState(Qt::WindowFullScreen);
  714         else
  715             gr->widget->setWindowState(Qt::WindowMaximized);
  716     }
  717 #endif
  718     return 1;
  719 }
  720 
  721 #ifdef SAILFISH_OS
  722 static void keep_display_on(struct graphics_priv* priv) {
  723     //        dbg(lvl_debug,"enter");
  724     QDBusConnection system = QDBusConnection::connectToBus(QDBusConnection::SystemBus, "system");
  725     QDBusInterface interface("com.nokia.mce", "/com/nokia/mce/request", "com.nokia.mce.request", system);
  726 
  727     interface.call(QLatin1String("req_display_blanking_pause"));
  728 }
  729 #endif
  730 
  731 static void graphics_qt5_disable_suspend(struct window* w) {
  732 //        dbg(lvl_debug,"enter");
  733 #ifdef SAILFISH_OS
  734     struct graphics_priv* gr;
  735     gr = (struct graphics_priv*)w->priv;
  736     keep_display_on(gr);
  737     /* to keep display on, d-bus trigger must be called at least once per second.
  738          * to cope with fuzz, trigger it once per 30 seconds */
  739     gr->display_on_cb = callback_new_1(callback_cast(keep_display_on), gr);
  740     gr->display_on_ev = event_add_timeout(30000, 1, gr->display_on_cb);
  741 #endif
  742 }
  743 
  744 static void* get_data(struct graphics_priv* this_priv, char const* type) {
  745     //        dbg(lvl_debug,"enter: %s", type);
  746     if (strcmp(type, "window") == 0) {
  747         struct window* win;
  748         //                dbg(lvl_debug,"window detected");
  749         win = g_new0(struct window, 1);
  750         win->priv = this_priv;
  751         win->fullscreen = graphics_qt5_fullscreen;
  752         win->disable_suspend = graphics_qt5_disable_suspend;
  753         resize_callback(this_priv, this_priv->pixmap->width(), this_priv->pixmap->height());
  754         return win;
  755     }
  756     if (strcmp(type, "engine") == 0) {
  757         dbg(lvl_debug, "Hand over QQmlApplicationEngine");
  758         return (this_priv->engine);
  759     }
  760     return NULL;
  761 }
  762 
  763 static void image_free(struct graphics_priv* gr, struct graphics_image_priv* priv) {
  764     //        dbg(lvl_debug,"enter");
  765     delete (priv->pixmap);
  766     g_free(priv);
  767 }
  768 
  769 /**
  770  * @brief   Calculate pixel space required for font display.
  771  * @param   gr  own private context
  772  * @param   font    font context to use (allocated by font_new)
  773  * @param   text    String to calculate bbox for
  774  * @param   dx  transformation matrix (16.16 fixpoint)
  775  * @param   dy  transformation matrix (16.16 fixpoint)
  776  * @param   ret point array to fill. (low left, top left, top right, low right)
  777  * @param   estimate    ???
  778  *
  779  * Calculates the bounding box around the given text.
  780  */
  781 static void get_text_bbox(struct graphics_priv* gr, struct graphics_font_priv* font, char* text, int dx, int dy,
  782                           struct point* ret, int estimate) {
  783     int i;
  784     struct point pt;
  785     QString tmp = QString::fromUtf8(text);
  786     QRect r;
  787     //        dbg(lvl_debug,"enter %s %d %d", text, dx, dy);
  788 
  789     /* use QFontMetrix for bbox calculation as we do not always have a painter */
  790     QFontMetrics fm(*font->font);
  791     r = fm.boundingRect(tmp);
  792 
  793     /* low left */
  794     ret[0].x = r.left();
  795     ret[0].y = r.bottom();
  796     /* top left */
  797     ret[1].x = r.left();
  798     ret[1].y = r.top();
  799     /* top right */
  800     ret[2].x = r.right();
  801     ret[2].y = r.top();
  802     /* low right */
  803     ret[3].x = r.right();
  804     ret[3].y = r.bottom();
  805     /* transform bbox if rotated */
  806     if (dy != 0 || dx != 0x10000) {
  807         for (i = 0; i < 4; i++) {
  808             pt = ret[i];
  809             ret[i].x = (pt.x * dx - pt.y * dy) / 0x10000;
  810             ret[i].y = (pt.y * dx + pt.x * dy) / 0x10000;
  811         }
  812     }
  813 }
  814 
  815 static void overlay_disable(struct graphics_priv* gr, int disable) {
  816     //dbg(lvl_error,"enter gr=%p, %d", gr, disable);
  817     gr->disable = disable;
  818 #if USE_QWIDGET
  819     /* call repaint on widget */
  820     if (gr->widget != NULL)
  821         gr->widget->repaint(gr->x, gr->y, gr->pixmap->width(), gr->pixmap->height());
  822 #endif
  823 #if USE_QML
  824     if (gr->GPriv != NULL)
  825         gr->GPriv->emit_update();
  826 
  827 #endif
  828 }
  829 
  830 static void overlay_resize(struct graphics_priv* gr, struct point* p, int w, int h, int wraparound) {
  831     //        dbg(lvl_debug,"enter %d %d %d %d %d", p->x, p->y, w, h, wraparound);
  832     gr->x = p->x;
  833     gr->y = p->y;
  834     if (gr->painter != NULL) {
  835         delete (gr->painter);
  836     }
  837     /* replacing the pixmap clears the content. Only neccesary if size actually changes */
  838     if((gr->pixmap->height() != h) || (gr->pixmap->width() != w)) {
  839         delete (gr->pixmap);
  840         gr->pixmap = new QPixmap(w, h);
  841         gr->pixmap->fill(Qt::transparent);
  842     }
  843     if (gr->painter != NULL)
  844         gr->painter = new QPainter(gr->pixmap);
  845 #if USE_QWIDGET
  846     /* call repaint on widget */
  847     if (gr->widget != NULL)
  848         gr->widget->repaint(gr->x, gr->y, gr->pixmap->width(), gr->pixmap->height());
  849 #endif
  850 #if USE_QML
  851     if (gr->GPriv != NULL)
  852         gr->GPriv->emit_update();
  853 
  854 #endif
  855 }
  856 
  857 /**
  858  * @brief Return number of dots per inch
  859  * @param gr self handle
  860  * @return dpi value
  861  */
  862 static navit_float get_dpi(struct graphics_priv * gr) {
  863     qreal dpi = 96;
  864     QScreen* primary = navit_app->primaryScreen();
  865     if (primary != NULL) {
  866         dpi = primary->physicalDotsPerInch();
  867     }
  868     return (navit_float)dpi;
  869 }
  870 
  871 static struct graphics_methods graphics_methods = {
  872     graphics_destroy,
  873     draw_mode,
  874     draw_lines,
  875     draw_polygon,
  876     draw_rectangle,
  877     draw_circle,
  878     draw_text,
  879     draw_image,
  880     NULL,
  881     draw_drag,
  882     font_new,
  883     gc_new,
  884     background_gc,
  885     overlay_new,
  886     image_new,
  887     get_data,
  888     image_free,
  889     get_text_bbox,
  890     overlay_disable,
  891     overlay_resize,
  892     NULL, //set_attr
  893     NULL, //show_native_keyboard
  894     NULL, //hide_native_keyboard
  895     get_dpi,
  896     draw_polygon_with_holes
  897 };
  898 
  899 /* create new graphics context on given context */
  900 static struct graphics_priv* overlay_new(struct graphics_priv* gr, struct graphics_methods* meth, struct point* p,
  901         int w, int h, int wraparound) {
  902     struct graphics_priv* graphics_priv = NULL;
  903     graphics_priv = g_new0(struct graphics_priv, 1);
  904     *meth = graphics_methods;
  905 #if HAVE_FREETYPE
  906     if (gr->font_freetype_new) {
  907         graphics_priv->font_freetype_new = gr->font_freetype_new;
  908         gr->font_freetype_new(&graphics_priv->freetype_methods);
  909         meth->font_new = (struct graphics_font_priv * (*)(struct graphics_priv*, struct graphics_font_methods*, char*, int,
  910                           int))graphics_priv->freetype_methods.font_new;
  911         meth->get_text_bbox = (void (*)(struct graphics_priv*, struct graphics_font_priv*, char*, int, int, struct point*,
  912                                         int))graphics_priv->freetype_methods.get_text_bbox;
  913     }
  914 #endif
  915 #if USE_QML
  916     graphics_priv->window = gr->window;
  917     graphics_priv->GPriv = gr->GPriv;
  918 #endif
  919 #if USE_QWIDGET
  920     graphics_priv->widget = gr->widget;
  921 #endif
  922     graphics_priv->x = p->x;
  923     graphics_priv->y = p->y;
  924     graphics_priv->disable = false;
  925     graphics_priv->callbacks = gr->callbacks;
  926     graphics_priv->pixmap = new QPixmap(w, h);
  927     graphics_priv->pixmap->fill(Qt::transparent);
  928     graphics_priv->painter = NULL;
  929     graphics_priv->use_count = 0;
  930     graphics_priv->parent = gr;
  931     graphics_priv->overlays = g_hash_table_new(NULL, NULL);
  932     graphics_priv->scroll_x = 0;
  933     graphics_priv->scroll_y = 0;
  934     graphics_priv->root = false;
  935     graphics_priv->argc = 0;
  936     graphics_priv->argv[0] = NULL;
  937     /* register on parent */
  938     g_hash_table_insert(gr->overlays, graphics_priv, graphics_priv);
  939     //        dbg(lvl_debug,"New overlay: %p", graphics_priv);
  940 
  941     return graphics_priv;
  942 }
  943 
  944 /* create application and initial graphics context */
  945 static struct graphics_priv* graphics_qt5_new(struct navit* nav, struct graphics_methods* meth, struct attr** attrs,
  946         struct callback_list* cbl) {
  947     struct graphics_priv* graphics_priv = NULL;
  948     struct attr* event_loop_system = NULL;
  949     struct attr* platform = NULL;
  950     struct attr* fullscreen = NULL;
  951     struct attr* attr_widget = NULL;
  952     bool use_qml = USE_QML;
  953     bool use_qwidget = USE_QWIDGET;
  954 
  955     //dbg(lvl_debug,"enter");
  956 
  957     /* get qt widget attr */
  958     if ((attr_widget = attr_search(attrs, attr_qt5_widget))) {
  959         /* check if we shall use qml */
  960         if (strcmp(attr_widget->u.str, "qwidget") == 0) {
  961             use_qml = false;
  962         }
  963         /* check if we shall use qwidget */
  964         if (strcmp(attr_widget->u.str, "qml") == 0) {
  965             use_qwidget = false;
  966         }
  967     }
  968     if (use_qml && use_qwidget) {
  969         /* both are possible, default to QML */
  970         use_qwidget = false;
  971     }
  972 
  973     /*register graphic methods by copying in our predefined ones */
  974     *meth = graphics_methods;
  975 
  976     /* get event loop from config and request event loop*/
  977     event_loop_system = attr_search(attrs, attr_event_loop_system);
  978     if (event_loop_system && event_loop_system->u.str) {
  979         //dbg(lvl_debug, "event_system is %s", event_loop_system->u.str);
  980         if (!event_request_system(event_loop_system->u.str, "graphics_qt5"))
  981             return NULL;
  982     } else {
  983         /* no event system requested by config. Default to our own */
  984         if (!event_request_system("qt5", "graphics_qt5"))
  985             return NULL;
  986     }
  987 
  988 #if HAVE_FREETYPE
  989     struct font_priv* (*font_freetype_new)(void* meth);
  990     /* get font plugin if present */
  991     font_freetype_new = (struct font_priv * (*)(void*))plugin_get_category_font("freetype");
  992     if (!font_freetype_new) {
  993         dbg(lvl_error, "no freetype");
  994         return NULL;
  995     }
  996 #endif
  997 
  998     /* create root graphics layer */
  999     graphics_priv = g_new0(struct graphics_priv, 1);
 1000     /* Prepare argc and argv to call Qt application*/
 1001     graphics_priv->root = true;
 1002     graphics_priv->argc = 0;
 1003     graphics_priv->argv[graphics_priv->argc] = g_strdup("navit");
 1004     graphics_priv->argc++;
 1005     /* Get qt platform from config */
 1006     if ((platform = attr_search(attrs, attr_qt5_platform))) {
 1007         graphics_priv->argv[graphics_priv->argc] = g_strdup("-platform");
 1008         graphics_priv->argc++;
 1009         graphics_priv->argv[graphics_priv->argc] = g_strdup(platform->u.str);
 1010         graphics_priv->argc++;
 1011     }
 1012     /* create surrounding application */
 1013 #if USE_QWIDGET
 1014     QApplication* internal_app = new QApplication(graphics_priv->argc, graphics_priv->argv);
 1015     navit_app = internal_app;
 1016 #else
 1017     navit_app = new QGuiApplication(graphics_priv->argc, graphics_priv->argv);
 1018 #endif
 1019 
 1020 #if HAVE_FREETYPE
 1021     graphics_priv->font_freetype_new = font_freetype_new;
 1022     font_freetype_new(&graphics_priv->freetype_methods);
 1023     meth->font_new = (struct graphics_font_priv * (*)(struct graphics_priv*, struct graphics_font_methods*, char*, int,
 1024                       int))graphics_priv->freetype_methods.font_new;
 1025     meth->get_text_bbox = (void (*)(struct graphics_priv*, struct graphics_font_priv*, char*, int, int, struct point*,
 1026                                     int))graphics_priv->freetype_methods.get_text_bbox;
 1027 #endif
 1028     graphics_priv->callbacks = cbl;
 1029     graphics_priv->pixmap = NULL;
 1030     graphics_priv->use_count = 0;
 1031     graphics_priv->painter = NULL;
 1032     graphics_priv->parent = NULL;
 1033     graphics_priv->overlays = g_hash_table_new(NULL, NULL);
 1034     graphics_priv->x = 0;
 1035     graphics_priv->y = 0;
 1036     graphics_priv->disable = 0;
 1037     graphics_priv->scroll_x = 0;
 1038     graphics_priv->scroll_y = 0;
 1039 #if USE_QML
 1040     graphics_priv->engine = NULL;
 1041     graphics_priv->window = NULL;
 1042     graphics_priv->GPriv = NULL;
 1043     if (use_qml) {
 1044         /* register our QtQuick widget to allow it's usage within QML */
 1045         qmlRegisterType<QNavitQuick>("com.navit.graphics_qt5", 1, 0, "QNavitQuick");
 1046         /* get our qml application from embedded resources. May be replaced by the
 1047              * QtQuick gui component if enabled */
 1048         graphics_priv->engine = new QQmlApplicationEngine();
 1049         if (graphics_priv->engine != NULL) {
 1050             graphics_priv->GPriv = new GraphicsPriv(graphics_priv);
 1051             QQmlContext* context = graphics_priv->engine->rootContext();
 1052             context->setContextProperty("graphics_qt5_context", graphics_priv->GPriv);
 1053             graphics_priv->engine->load(QUrl("qrc:///loader.qml"));
 1054             /* Get the engine's root window (for resizing) */
 1055             QObject* toplevel = graphics_priv->engine->rootObjects().value(0);
 1056             graphics_priv->window = qobject_cast<QQuickWindow*>(toplevel);
 1057         }
 1058     }
 1059 #endif
 1060 #if USE_QWIDGET
 1061     graphics_priv->widget = NULL;
 1062     if (use_qwidget) {
 1063         graphics_priv->widget = new QNavitWidget(graphics_priv, NULL, Qt::Window);
 1064     }
 1065 #endif
 1066     if ((fullscreen = attr_search(attrs, attr_fullscreen)) && (fullscreen->u.num)) {
 1067         /* show this maximized */
 1068 #if USE_QML
 1069         if (graphics_priv->window != NULL)
 1070             graphics_priv->window->setWindowState(Qt::WindowFullScreen);
 1071 #endif
 1072 #if USE_QWIDGET
 1073         if (graphics_priv->widget != NULL)
 1074             graphics_priv->widget->setWindowState(Qt::WindowFullScreen);
 1075 #endif
 1076     } else {
 1077         /* not maximized. Check what size to use then */
 1078         struct attr* w = NULL;
 1079         struct attr* h = NULL;
 1080         /* default to desktop size if nothing else is given */
 1081         QRect geomet;
 1082         geomet.setHeight(100);
 1083         geomet.setWidth(100);
 1084         /* get desktop size */
 1085         QScreen* primary = navit_app->primaryScreen();
 1086         if (primary != NULL) {
 1087             geomet = primary->availableGeometry();
 1088         }
 1089         /* check for height */
 1090         if ((h = attr_search(attrs, attr_h)) && (h->u.num > 100))
 1091             geomet.setHeight(h->u.num);
 1092         /* check for width */
 1093         if ((w = attr_search(attrs, attr_w)) && (w->u.num > 100))
 1094             geomet.setWidth(w->u.num);
 1095 #if USE_QML
 1096         if (graphics_priv->window != NULL) {
 1097             graphics_priv->window->resize(geomet.width(), geomet.height());
 1098             //graphics_priv->window->setFixedSize(geomet.width(), geomet.height());
 1099         }
 1100 #endif
 1101 #if USE_QWIDGET
 1102         if (graphics_priv->widget != NULL) {
 1103             graphics_priv->widget->resize(geomet.width(), geomet.height());
 1104             //graphics_priv->widget->setFixedSize(geomet.width(), geomet.height());
 1105         }
 1106 #endif
 1107     }
 1108     /* generate initial pixmap same size as window */
 1109     if (graphics_priv->pixmap == NULL) {
 1110 #if USE_QML
 1111         if (graphics_priv->window != NULL)
 1112             graphics_priv->pixmap = new QPixmap(graphics_priv->window->size());
 1113 #endif
 1114 #if USE_QWIDGET
 1115         if (graphics_priv->widget != NULL)
 1116             graphics_priv->pixmap = new QPixmap(graphics_priv->widget->size());
 1117 #endif
 1118         if (graphics_priv->pixmap == NULL)
 1119             graphics_priv->pixmap = new QPixmap(100, 100);
 1120         graphics_priv->pixmap->fill(Qt::black);
 1121     }
 1122 
 1123     /* tell Navit our geometry */
 1124     resize_callback(graphics_priv, graphics_priv->pixmap->width(), graphics_priv->pixmap->height());
 1125 
 1126     /* show our window */
 1127 #if USE_QML
 1128     if (graphics_priv->window != NULL)
 1129         graphics_priv->window->show();
 1130 #endif
 1131 #if USE_QWIDGET
 1132     if (graphics_priv->widget != NULL)
 1133         graphics_priv->widget->show();
 1134 #endif
 1135 
 1136     return graphics_priv;
 1137 }
 1138 
 1139 void plugin_init(void) {
 1140 #if USE_QML
 1141     Q_INIT_RESOURCE(graphics_qt5);
 1142 #endif
 1143     //        dbg(lvl_debug,"enter");
 1144     plugin_register_category_graphics("qt5", graphics_qt5_new);
 1145     qt5_event_init();
 1146 }