"Fossies" - the Fresh Open Source Software Archive

Member "poppler-0.82.0/glib/poppler-action.cc" (25 Oct 2019, 17062 Bytes) of package /linux/misc/poppler-0.82.0.tar.xz:


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 "poppler-action.cc" see the Fossies "Dox" file reference documentation.

    1 /* poppler-action.cc: glib wrapper for poppler        -*- c-basic-offset: 8 -*-
    2  * Copyright (C) 2005, Red Hat, Inc.
    3  *
    4  * This program is free software; you can redistribute it and/or modify
    5  * it under the terms of the GNU General Public License as published by
    6  * the Free Software Foundation; either version 2, or (at your option)
    7  * any later version.
    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 Free Software
   16  * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
   17  */
   18 
   19 #include "poppler.h"
   20 #include "poppler-private.h"
   21 
   22 /**
   23  * SECTION:poppler-action
   24  * @short_description: Action links
   25  * @title: PopplerAction
   26  */
   27 
   28 POPPLER_DEFINE_BOXED_TYPE (PopplerDest, poppler_dest, poppler_dest_copy, poppler_dest_free)
   29 
   30 /**
   31  * poppler_dest_copy:
   32  * @dest: a #PopplerDest
   33  *
   34  * Copies @dest, creating an identical #PopplerDest.
   35  *
   36  * Return value: a new destination identical to @dest
   37  **/
   38 PopplerDest *
   39 poppler_dest_copy (PopplerDest *dest)
   40 {
   41     PopplerDest *new_dest;
   42 
   43     new_dest = g_slice_dup (PopplerDest, dest);
   44 
   45     if (dest->named_dest)
   46         new_dest->named_dest = g_strdup (dest->named_dest);
   47 
   48     return new_dest;
   49 }
   50 
   51 
   52 /**
   53  * poppler_dest_free:
   54  * @dest: a #PopplerDest
   55  *
   56  * Frees @dest
   57  **/
   58 void
   59 poppler_dest_free (PopplerDest *dest)
   60 {
   61     if (!dest)
   62         return;
   63     
   64     if (dest->named_dest)
   65         g_free (dest->named_dest);
   66     
   67     g_slice_free (PopplerDest, dest);
   68 }
   69 
   70 static void
   71 poppler_action_layer_free (PopplerActionLayer *action_layer)
   72 {
   73     if (!action_layer)
   74         return;
   75 
   76     if (action_layer->layers) {
   77         g_list_foreach (action_layer->layers, (GFunc)g_object_unref, nullptr);
   78         g_list_free (action_layer->layers);
   79         action_layer->layers = nullptr;
   80     }
   81 
   82     g_slice_free (PopplerActionLayer, action_layer);
   83 }
   84 
   85 static PopplerActionLayer *
   86 poppler_action_layer_copy (PopplerActionLayer *action_layer)
   87 {
   88     PopplerActionLayer *retval = g_slice_dup (PopplerActionLayer, action_layer);
   89 
   90     retval->layers = g_list_copy (action_layer->layers);
   91     g_list_foreach (action_layer->layers, (GFunc)g_object_ref, nullptr);
   92 
   93     return retval;
   94 }
   95 
   96 POPPLER_DEFINE_BOXED_TYPE (PopplerAction, poppler_action, poppler_action_copy, poppler_action_free)
   97 
   98 /**
   99  * poppler_action_free:
  100  * @action: a #PopplerAction
  101  * 
  102  * Frees @action
  103  **/
  104 void
  105 poppler_action_free (PopplerAction *action)
  106 {
  107     if (action == nullptr)
  108         return;
  109 
  110     /* Action specific stuff */
  111     switch (action->type) {
  112     case POPPLER_ACTION_GOTO_DEST:
  113         poppler_dest_free (action->goto_dest.dest);
  114         break;
  115     case POPPLER_ACTION_GOTO_REMOTE:
  116         poppler_dest_free (action->goto_remote.dest);
  117         g_free (action->goto_remote.file_name);
  118         break;
  119     case POPPLER_ACTION_URI:
  120         g_free (action->uri.uri);
  121         break;
  122     case POPPLER_ACTION_LAUNCH:
  123         g_free (action->launch.file_name);
  124         g_free (action->launch.params);
  125         break;
  126     case POPPLER_ACTION_NAMED:
  127         g_free (action->named.named_dest);
  128         break;
  129     case POPPLER_ACTION_MOVIE:
  130         if (action->movie.movie)
  131             g_object_unref (action->movie.movie);
  132         break;
  133     case POPPLER_ACTION_RENDITION:
  134         if (action->rendition.media)
  135             g_object_unref (action->rendition.media);
  136         break;
  137     case POPPLER_ACTION_OCG_STATE:
  138         if (action->ocg_state.state_list) {
  139             g_list_foreach (action->ocg_state.state_list, (GFunc)poppler_action_layer_free, nullptr);
  140             g_list_free (action->ocg_state.state_list);
  141         }
  142         break;
  143     case POPPLER_ACTION_JAVASCRIPT:
  144         if (action->javascript.script)
  145             g_free (action->javascript.script);
  146         break;
  147     default:
  148         break;
  149     }
  150     
  151     g_free (action->any.title);
  152     g_slice_free (PopplerAction, action);
  153 }
  154 
  155 /**
  156  * poppler_action_copy:
  157  * @action: a #PopplerAction
  158  * 
  159  * Copies @action, creating an identical #PopplerAction.
  160  * 
  161  * Return value: a new action identical to @action
  162  **/
  163 PopplerAction *
  164 poppler_action_copy (PopplerAction *action)
  165 {
  166     PopplerAction *new_action;
  167 
  168     g_return_val_if_fail (action != nullptr, NULL);
  169 
  170     /* Do a straight copy of the memory */
  171     new_action = g_slice_dup (PopplerAction, action);
  172 
  173     if (action->any.title != nullptr)
  174         new_action->any.title = g_strdup (action->any.title);
  175 
  176     switch (action->type) {
  177     case POPPLER_ACTION_GOTO_DEST:
  178         new_action->goto_dest.dest = poppler_dest_copy (action->goto_dest.dest);
  179         break;
  180     case POPPLER_ACTION_GOTO_REMOTE:
  181         new_action->goto_remote.dest = poppler_dest_copy (action->goto_remote.dest);
  182         if (action->goto_remote.file_name)
  183             new_action->goto_remote.file_name = g_strdup (action->goto_remote.file_name);
  184         break;
  185     case POPPLER_ACTION_URI:
  186         if (action->uri.uri)
  187             new_action->uri.uri = g_strdup (action->uri.uri);
  188         break;
  189     case POPPLER_ACTION_LAUNCH:
  190         if (action->launch.file_name)
  191             new_action->launch.file_name = g_strdup (action->launch.file_name);
  192         if (action->launch.params)
  193             new_action->launch.params = g_strdup (action->launch.params);
  194         break;
  195     case POPPLER_ACTION_NAMED:
  196         if (action->named.named_dest)
  197             new_action->named.named_dest = g_strdup (action->named.named_dest);
  198         break;
  199     case POPPLER_ACTION_MOVIE:
  200         if (action->movie.movie)
  201             new_action->movie.movie = (PopplerMovie *)g_object_ref (action->movie.movie);
  202         break;
  203     case POPPLER_ACTION_RENDITION:
  204         if (action->rendition.media)
  205             new_action->rendition.media = (PopplerMedia *)g_object_ref (action->rendition.media);
  206         break;
  207     case POPPLER_ACTION_OCG_STATE:
  208         if (action->ocg_state.state_list) {
  209             GList *l;
  210             GList *new_list = nullptr;
  211 
  212             for (l = action->ocg_state.state_list; l; l = g_list_next (l)) {
  213                 PopplerActionLayer *alayer = (PopplerActionLayer *)l->data;
  214                 new_list = g_list_prepend (new_list, poppler_action_layer_copy (alayer));
  215             }
  216 
  217             new_action->ocg_state.state_list = g_list_reverse (new_list);
  218         }
  219 
  220         break;
  221     case POPPLER_ACTION_JAVASCRIPT:
  222         if (action->javascript.script)
  223             new_action->javascript.script = g_strdup (action->javascript.script);
  224         break;
  225     default:
  226         break;
  227     }
  228         
  229     return new_action;
  230 }
  231 
  232 static
  233 PopplerDest *
  234 dest_new_goto (PopplerDocument *document,
  235            const LinkDest        *link_dest)
  236 {
  237     PopplerDest *dest;
  238 
  239     dest = g_slice_new0 (PopplerDest);
  240 
  241     if (link_dest == nullptr) {
  242         dest->type = POPPLER_DEST_UNKNOWN;
  243         return dest;
  244     }
  245 
  246     switch (link_dest->getKind ()) {
  247     case destXYZ:
  248         dest->type = POPPLER_DEST_XYZ;
  249         break;
  250     case destFit:
  251         dest->type = POPPLER_DEST_FIT;
  252         break;
  253     case destFitH:
  254         dest->type = POPPLER_DEST_FITH;
  255         break;
  256     case destFitV:
  257         dest->type = POPPLER_DEST_FITV;
  258         break;
  259     case destFitR:
  260         dest->type = POPPLER_DEST_FITR;
  261         break;
  262     case destFitB:
  263         dest->type = POPPLER_DEST_FITB;
  264         break;
  265     case destFitBH:
  266         dest->type = POPPLER_DEST_FITBH;
  267         break;
  268     case destFitBV:
  269         dest->type = POPPLER_DEST_FITBV;
  270         break;
  271     default:
  272         dest->type = POPPLER_DEST_UNKNOWN;
  273     }
  274 
  275     if (link_dest->isPageRef ()) {
  276         if (document) {
  277             const Ref page_ref = link_dest->getPageRef ();
  278             dest->page_num = document->doc->findPage (page_ref);
  279         } else {
  280             /* FIXME: We don't keep areound the page_ref for the
  281              * remote doc, so we can't look this up.  Guess that
  282              * it's 0*/
  283             dest->page_num = 0;
  284         }
  285     } else {
  286         dest->page_num = link_dest->getPageNum ();
  287     }
  288 
  289     dest->left = link_dest->getLeft ();
  290     dest->bottom = link_dest->getBottom ();
  291     dest->right = link_dest->getRight ();
  292     dest->top = link_dest->getTop ();
  293     dest->zoom = link_dest->getZoom ();
  294     dest->change_left = link_dest->getChangeLeft ();
  295     dest->change_top = link_dest->getChangeTop ();
  296     dest->change_zoom = link_dest->getChangeZoom ();
  297     
  298     if (document && dest->page_num > 0) {
  299         PopplerPage *page;
  300 
  301         page = poppler_document_get_page (document, dest->page_num - 1);
  302 
  303         if (page) {
  304             dest->left -= page->page->getCropBox ()->x1;
  305             dest->bottom -= page->page->getCropBox ()->x1;
  306             dest->right -= page->page->getCropBox ()->y1;
  307             dest->top -= page->page->getCropBox ()->y1;
  308 
  309             g_object_unref (page);
  310         } else {
  311             g_warning ("Invalid page %d in Link Destination\n", dest->page_num);
  312             dest->page_num = 0;
  313         }
  314     }
  315     
  316     return dest;
  317 }
  318 
  319 static PopplerDest *
  320 dest_new_named (const GooString *named_dest)
  321 {
  322     PopplerDest *dest;
  323 
  324     dest = g_slice_new0 (PopplerDest);
  325 
  326     if (named_dest == nullptr) {
  327         dest->type = POPPLER_DEST_UNKNOWN;
  328         return dest;
  329     }
  330 
  331     const std::string& str = named_dest->toStr ();
  332 
  333     dest->type = POPPLER_DEST_NAMED;
  334     dest->named_dest = poppler_named_dest_from_bytestring((const guint8*)str.data (),
  335                                   str.size ());
  336 
  337     return dest;
  338 }
  339 
  340 static void
  341 build_goto_dest (PopplerDocument *document,
  342          PopplerAction   *action,
  343          const LinkGoTo        *link)
  344 {
  345     const LinkDest *link_dest;
  346     const GooString *named_dest;
  347 
  348     /* Return if it isn't OK */
  349     if (! link->isOk ()) {
  350         action->goto_dest.dest = dest_new_goto (nullptr, nullptr);
  351         return;
  352     }
  353     
  354     link_dest = link->getDest ();
  355     named_dest = link->getNamedDest ();
  356 
  357     if (link_dest != nullptr) {
  358         action->goto_dest.dest = dest_new_goto (document, link_dest);
  359     } else if (named_dest != nullptr) {
  360         action->goto_dest.dest = dest_new_named (named_dest);
  361     } else {
  362         action->goto_dest.dest = dest_new_goto (document, nullptr);
  363     }
  364 }
  365 
  366 static void
  367 build_goto_remote (PopplerAction *action,
  368            const LinkGoToR     *link)
  369 {
  370     const LinkDest *link_dest;
  371     const GooString *named_dest;
  372     
  373     /* Return if it isn't OK */
  374     if (! link->isOk ()) {
  375         action->goto_remote.dest = dest_new_goto (nullptr, nullptr);
  376         return;
  377     }
  378 
  379     action->goto_remote.file_name = _poppler_goo_string_to_utf8 (link->getFileName());
  380 
  381     link_dest = link->getDest ();
  382     named_dest = link->getNamedDest ();
  383     
  384     if (link_dest != nullptr) {
  385         action->goto_remote.dest = dest_new_goto (nullptr, link_dest);
  386     } else if (named_dest != nullptr) {
  387         action->goto_remote.dest = dest_new_named (named_dest);
  388     } else {
  389         action->goto_remote.dest = dest_new_goto (nullptr, nullptr);
  390     }
  391 }
  392 
  393 static void
  394 build_launch (PopplerAction *action,
  395           const LinkLaunch    *link)
  396 {
  397     if (link->getFileName()) {
  398         action->launch.file_name = g_strdup (link->getFileName()->c_str ());
  399     }
  400     if (link->getParams()) {
  401         action->launch.params = g_strdup (link->getParams()->c_str ());
  402     }
  403 }
  404 
  405 static void
  406 build_uri (PopplerAction *action,
  407        const LinkURI       *link)
  408 {
  409     const gchar *uri;
  410 
  411     uri = link->getURI()->c_str ();
  412     if (uri != nullptr)
  413         action->uri.uri = g_strdup (uri);
  414 }
  415 
  416 static void
  417 build_named (PopplerAction *action,
  418          const LinkNamed     *link)
  419 {
  420     const gchar *name;
  421 
  422     name = link->getName ()->c_str ();
  423     if (name != nullptr)
  424         action->named.named_dest = g_strdup (name);
  425 }
  426 
  427 static AnnotMovie *
  428 find_annot_movie_for_action (PopplerDocument *document,
  429                  const LinkMovie       *link)
  430 {
  431   AnnotMovie *annot = nullptr;
  432   XRef *xref = document->doc->getXRef ();
  433   Object annotObj;
  434 
  435   if (link->hasAnnotRef ()) {
  436     const Ref *ref = link->getAnnotRef ();
  437 
  438     annotObj = xref->fetch (*ref);
  439   } else if (link->hasAnnotTitle ()) {
  440     const GooString *title = link->getAnnotTitle ();
  441     int i;
  442 
  443     for (i = 1; i <= document->doc->getNumPages (); ++i) {
  444       Page *p = document->doc->getPage (i);
  445       if (!p) continue;
  446 
  447       Object annots = p->getAnnotsObject ();
  448       if (annots.isArray ()) {
  449         int j;
  450     bool found = false;
  451 
  452     for (j = 0; j < annots.arrayGetLength () && !found; ++j) {
  453           annotObj = annots.arrayGet(j);
  454           if (annotObj.isDict()) {
  455         Object obj1 = annotObj.dictLookup ("Subtype");
  456         if (!obj1.isName ("Movie")) {
  457           continue;
  458         }
  459 
  460         obj1 = annotObj.dictLookup ("T");
  461         if (obj1.isString()) {
  462           const GooString *t = obj1.getString ();
  463 
  464           if (title->cmp(t) == 0)
  465             found = true;
  466         }
  467       }
  468       if (!found)
  469         annotObj.setToNull ();
  470     }
  471     if (found) {
  472       break;
  473     } else {
  474           annotObj.setToNull ();
  475     }
  476       }
  477     }
  478   }
  479 
  480   if (annotObj.isDict ()) {
  481     Object tmp;
  482 
  483     annot = new AnnotMovie (document->doc, std::move(annotObj), &tmp);
  484     if (!annot->isOk ()) {
  485       delete annot;
  486       annot = nullptr;
  487     }
  488   }
  489 
  490   return annot;
  491 }
  492 
  493 static void
  494 build_movie (PopplerDocument *document,
  495          PopplerAction   *action,
  496          const LinkMovie       *link)
  497 {
  498     AnnotMovie *annot;
  499 
  500     switch (link->getOperation ()) {
  501     case LinkMovie::operationTypePause:
  502         action->movie.operation = POPPLER_ACTION_MOVIE_PAUSE;
  503         break;
  504     case LinkMovie::operationTypeResume:
  505         action->movie.operation = POPPLER_ACTION_MOVIE_RESUME;
  506         break;
  507     case LinkMovie::operationTypeStop:
  508         action->movie.operation = POPPLER_ACTION_MOVIE_STOP;
  509         break;
  510     default:
  511     case LinkMovie::operationTypePlay:
  512         action->movie.operation = POPPLER_ACTION_MOVIE_PLAY;
  513         break;
  514     }
  515 
  516     annot = find_annot_movie_for_action (document, link);
  517     if (annot) {
  518         action->movie.movie = _poppler_movie_new (annot->getMovie());
  519         delete annot;
  520     }
  521 }
  522 
  523 static void
  524 build_javascript (PopplerAction *action,
  525           const LinkJavaScript *link)
  526 {
  527     const GooString *script;
  528 
  529     script = link->getScript();
  530     if (script)
  531         action->javascript.script = _poppler_goo_string_to_utf8 (script);
  532 
  533 }
  534 
  535 static void
  536 build_rendition (PopplerAction *action,
  537          const LinkRendition *link)
  538 {
  539     action->rendition.op = link->getOperation();
  540     if (link->hasRenditionObject())
  541         action->rendition.media = _poppler_media_new (link->getMedia());
  542     // TODO: annotation reference
  543 }
  544 
  545 static PopplerLayer *
  546 get_layer_for_ref (PopplerDocument *document,
  547            GList           *layers,
  548            Ref             *ref,
  549            gboolean         preserve_rb)
  550 {
  551     GList *l;
  552 
  553     for (l = layers; l; l = g_list_next (l)) {
  554         Layer *layer = (Layer *)l->data;
  555 
  556         if (layer->oc) {
  557             const Ref ocgRef = layer->oc->getRef();
  558 
  559             if (*ref == ocgRef) {
  560                 GList *rb_group = nullptr;
  561 
  562                 if (preserve_rb)
  563                     rb_group = _poppler_document_get_layer_rbgroup (document, layer);
  564                 return _poppler_layer_new (document, layer, rb_group);
  565             }
  566         }
  567 
  568         if (layer->kids) {
  569             PopplerLayer *retval = get_layer_for_ref (document, layer->kids, ref, preserve_rb);
  570             if (retval)
  571                 return retval;
  572         }
  573     }
  574 
  575     return nullptr;
  576 }
  577 
  578 static void
  579 build_ocg_state (PopplerDocument *document,
  580          PopplerAction   *action,
  581          const LinkOCGState    *ocg_state)
  582 {
  583     const std::vector<LinkOCGState::StateList*> *st_list = ocg_state->getStateList();
  584     bool    preserve_rb = ocg_state->getPreserveRB();
  585     GList   *layer_state = nullptr;
  586 
  587     if (!document->layers) {
  588         if (!_poppler_document_get_layers (document))
  589             return;
  590     }
  591 
  592     for (std::size_t i = 0; i < st_list->size(); ++i) {
  593         LinkOCGState::StateList *list = (*st_list)[i];
  594         PopplerActionLayer *action_layer = g_slice_new0 (PopplerActionLayer);
  595 
  596         switch (list->st) {
  597         case LinkOCGState::On:
  598             action_layer->action = POPPLER_ACTION_LAYER_ON;
  599             break;
  600         case LinkOCGState::Off:
  601             action_layer->action = POPPLER_ACTION_LAYER_OFF;
  602             break;
  603         case LinkOCGState::Toggle:
  604             action_layer->action = POPPLER_ACTION_LAYER_TOGGLE;
  605             break;
  606         }
  607 
  608         for (std::size_t j = 0; j < list->list->size(); ++j) {
  609             Ref *ref = (*list->list)[j];
  610             PopplerLayer *layer = get_layer_for_ref (document, document->layers, ref, preserve_rb);
  611 
  612             action_layer->layers = g_list_prepend (action_layer->layers, layer);
  613         }
  614 
  615         layer_state = g_list_prepend (layer_state, action_layer);
  616     }
  617 
  618     action->ocg_state.state_list = g_list_reverse (layer_state);
  619 }
  620 
  621 PopplerAction *
  622 _poppler_action_new (PopplerDocument *document,
  623              const LinkAction      *link,
  624              const gchar     *title)
  625 {
  626     PopplerAction *action;
  627 
  628     action = g_slice_new0 (PopplerAction);
  629 
  630     if (title)
  631         action->any.title = g_strdup (title);
  632 
  633     if (link == nullptr) {
  634         action->type = POPPLER_ACTION_NONE;
  635         return action;
  636     }
  637 
  638     switch (link->getKind ()) {
  639     case actionGoTo:
  640         action->type = POPPLER_ACTION_GOTO_DEST;
  641         build_goto_dest (document, action, dynamic_cast <const LinkGoTo *> (link));
  642         break;
  643     case actionGoToR:
  644         action->type = POPPLER_ACTION_GOTO_REMOTE;
  645         build_goto_remote (action, dynamic_cast <const LinkGoToR *> (link));
  646         break;
  647     case actionLaunch:
  648         action->type = POPPLER_ACTION_LAUNCH;
  649         build_launch (action, dynamic_cast <const LinkLaunch *> (link));
  650         break;
  651     case actionURI:
  652         action->type = POPPLER_ACTION_URI;
  653         build_uri (action, dynamic_cast <const LinkURI *> (link));
  654         break;
  655     case actionNamed:
  656         action->type = POPPLER_ACTION_NAMED;
  657         build_named (action, dynamic_cast <const LinkNamed *> (link));
  658         break;
  659     case actionMovie:
  660         action->type = POPPLER_ACTION_MOVIE;
  661         build_movie (document, action, dynamic_cast<const LinkMovie*> (link));
  662         break;
  663     case actionRendition:
  664         action->type = POPPLER_ACTION_RENDITION;
  665         build_rendition (action, dynamic_cast<const LinkRendition*> (link));
  666         break;
  667     case actionOCGState:
  668         action->type = POPPLER_ACTION_OCG_STATE;
  669         build_ocg_state (document, action, dynamic_cast<const LinkOCGState*> (link));
  670         break;
  671     case actionJavaScript:
  672         action->type = POPPLER_ACTION_JAVASCRIPT;
  673         build_javascript (action, dynamic_cast<const LinkJavaScript*> (link));
  674         break;
  675     case actionUnknown:
  676     default:
  677         action->type = POPPLER_ACTION_UNKNOWN;
  678         break;
  679     }
  680 
  681     return action;
  682 }
  683 
  684 PopplerDest *
  685 _poppler_dest_new_goto (PopplerDocument *document,
  686             LinkDest        *link_dest)
  687 {
  688     return dest_new_goto (document, link_dest);
  689 }