LCOV - code coverage report
Current view: top level - sdext/source/pdfimport/tree - genericelements.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 95 234 40.6 %
Date: 2014-11-03 Functions: 22 30 73.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : #include "xmlemitter.hxx"
      22             : #include "genericelements.hxx"
      23             : #include "pdfiprocessor.hxx"
      24             : #include "pdfihelper.hxx"
      25             : #include "style.hxx"
      26             : 
      27             : 
      28             : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      29             : #include <basegfx/range/b2drange.hxx>
      30             : 
      31             : namespace pdfi
      32             : {
      33             : 
      34           8 : ElementFactory::~ElementFactory()
      35             : {
      36           8 : }
      37             : 
      38        1084 : Element::~Element()
      39             : {
      40        1428 :     while( !Children.empty() )
      41             :     {
      42         344 :         Element* pCurr( Children.front() );
      43         344 :         delete pCurr;
      44         344 :         Children.pop_front();
      45             :     }
      46         542 : }
      47             : 
      48         200 : void Element::applyToChildren( ElementTreeVisitor& rVisitor )
      49             : {
      50         884 :     for( std::list< Element* >::iterator it = Children.begin(); it != Children.end(); ++it )
      51         684 :         (*it)->visitedBy( rVisitor, it );
      52         200 : }
      53             : 
      54           0 : void Element::setParent( std::list<Element*>::iterator& el, Element* pNewParent )
      55             : {
      56           0 :     if( pNewParent )
      57             :     {
      58           0 :         pNewParent->Children.splice( pNewParent->Children.end(), (*el)->Parent->Children, el );
      59           0 :         (*el)->Parent = pNewParent;
      60             :     }
      61           0 : }
      62             : 
      63         274 : void Element::updateGeometryWith( const Element* pMergeFrom )
      64             : {
      65         274 :     if( w == 0 && h == 0 )
      66             :     {
      67         274 :         x = pMergeFrom->x;
      68         274 :         y = pMergeFrom->y;
      69         274 :         w = pMergeFrom->w;
      70         274 :         h = pMergeFrom->h;
      71             :     }
      72             :     else
      73             :     {
      74           0 :         if( pMergeFrom->x < x )
      75             :         {
      76           0 :             w += x - pMergeFrom->x;
      77           0 :             x = pMergeFrom->x;
      78             :         }
      79           0 :         if( pMergeFrom->x+pMergeFrom->w > x+w )
      80           0 :             w = pMergeFrom->w+pMergeFrom->x - x;
      81           0 :         if( pMergeFrom->y < y )
      82             :         {
      83           0 :             h += y - pMergeFrom->y;
      84           0 :             y = pMergeFrom->y;
      85             :         }
      86           0 :         if( pMergeFrom->y+pMergeFrom->h > y+h )
      87           0 :             h = pMergeFrom->h+pMergeFrom->y - y;
      88             :     }
      89         274 : }
      90             : 
      91             : 
      92             : #if OSL_DEBUG_LEVEL > 1
      93             : #include <typeinfo>
      94             : void Element::emitStructure( int nLevel)
      95             : {
      96             :     OSL_TRACE( "%*s<%s %p> (%.1f,%.1f)+(%.1fx%.1f)\n",
      97             :                nLevel, "", typeid( *this ).name(), this,
      98             :                x, y, w, h );
      99             :     for( std::list< Element* >::iterator it = Children.begin(); it != Children.end(); ++it )
     100             :         (*it)->emitStructure(nLevel+1 );
     101             :     OSL_TRACE( "%*s</%s>", nLevel, "", typeid( *this ).name() );
     102             : }
     103             : #endif
     104             : 
     105           0 : void ListElement::visitedBy( ElementTreeVisitor& visitor, const std::list< Element* >::const_iterator& )
     106             : {
     107             :     // this is only an inner node
     108           0 :     applyToChildren(visitor);
     109           0 : }
     110             : 
     111           0 : void HyperlinkElement::visitedBy( ElementTreeVisitor&                          rVisitor,
     112             :                                   const std::list< Element* >::const_iterator& rParentIt )
     113             : {
     114           0 :     rVisitor.visit(*this,rParentIt);
     115           0 : }
     116             : 
     117         898 : void TextElement::visitedBy( ElementTreeVisitor&                          rVisitor,
     118             :                              const std::list< Element* >::const_iterator& rParentIt )
     119             : {
     120         898 :     rVisitor.visit(*this,rParentIt);
     121         898 : }
     122             : 
     123         168 : void FrameElement::visitedBy( ElementTreeVisitor&                          rVisitor,
     124             :                               const std::list< Element* >::const_iterator& rParentIt )
     125             : {
     126         168 :     rVisitor.visit(*this,rParentIt);
     127         168 : }
     128             : 
     129          14 : void ImageElement::visitedBy( ElementTreeVisitor&                          rVisitor,
     130             :                               const std::list< Element* >::const_iterator& rParentIt)
     131             : {
     132          14 :     rVisitor.visit( *this, rParentIt);
     133          14 : }
     134             : 
     135          12 : PolyPolyElement::PolyPolyElement( Element*                       pParent,
     136             :                                   sal_Int32                      nGCId,
     137             :                                   const basegfx::B2DPolyPolygon& rPolyPoly,
     138             :                                   sal_Int8                       nAction )
     139             :     : DrawElement( pParent, nGCId ),
     140             :       PolyPoly( rPolyPoly ),
     141          12 :       Action( nAction )
     142             : {
     143          12 : }
     144             : 
     145          30 : void PolyPolyElement::updateGeometry()
     146             : {
     147          30 :     basegfx::B2DRange aRange;
     148          30 :     if( PolyPoly.areControlPointsUsed() )
     149          10 :         aRange = basegfx::tools::getRange( basegfx::tools::adaptiveSubdivideByAngle( PolyPoly ) );
     150             :     else
     151          20 :         aRange = basegfx::tools::getRange( PolyPoly );
     152          30 :     x = aRange.getMinX();
     153          30 :     y = aRange.getMinY();
     154          30 :     w = aRange.getWidth();
     155          30 :     h = aRange.getHeight();
     156             : 
     157             :     // fdo#32330 - non-closed paths will not show up filled in LibO
     158          30 :     if( Action & (PATH_FILL | PATH_EOFILL) )
     159          10 :         PolyPoly.setClosed(true);
     160          30 : }
     161             : 
     162          42 : void PolyPolyElement::visitedBy( ElementTreeVisitor&                          rVisitor,
     163             :                                  const std::list< Element* >::const_iterator& rParentIt)
     164             : {
     165          42 :     rVisitor.visit( *this, rParentIt);
     166          42 : }
     167             : 
     168             : #if OSL_DEBUG_LEVEL > 1
     169             : void PolyPolyElement::emitStructure( int nLevel)
     170             : {
     171             :     OSL_TRACE( "%*s<%s %p>", nLevel, "", typeid( *this ).name(), this  );
     172             :     OSL_TRACE( "path=" );
     173             :     int nPoly = PolyPoly.count();
     174             :     for( int i = 0; i < nPoly; i++ )
     175             :     {
     176             :         basegfx::B2DPolygon aPoly = PolyPoly.getB2DPolygon( i );
     177             :         int nPoints = aPoly.count();
     178             :         for( int n = 0; n < nPoints; n++ )
     179             :         {
     180             :             basegfx::B2DPoint aPoint = aPoly.getB2DPoint( n );
     181             :             OSL_TRACE( " (%g,%g)", aPoint.getX(), aPoint.getY() );
     182             :         }
     183             :         OSL_TRACE( "\n" );
     184             :     }
     185             :     for( std::list< Element* >::iterator it = Children.begin(); it != Children.end(); ++it )
     186             :         (*it)->emitStructure( nLevel+1 );
     187             :     OSL_TRACE( "%*s</%s>", nLevel, "", typeid( *this ).name() );
     188             : }
     189             : #endif
     190             : 
     191         156 : void ParagraphElement::visitedBy( ElementTreeVisitor&                          rVisitor,
     192             :                                   const std::list< Element* >::const_iterator& rParentIt )
     193             : {
     194         156 :     rVisitor.visit(*this,rParentIt);
     195         156 : }
     196             : 
     197           0 : bool ParagraphElement::isSingleLined( PDFIProcessor& rProc ) const
     198             : {
     199           0 :     std::list< Element* >::const_iterator it = Children.begin();
     200           0 :     TextElement* pText = NULL, *pLastText = NULL;
     201           0 :     while( it != Children.end() )
     202             :     {
     203             :         // a paragraph containing subparagraphs cannot be single lined
     204           0 :         if( dynamic_cast< ParagraphElement* >(*it) != NULL )
     205           0 :             return false;
     206             : 
     207           0 :         pText = dynamic_cast< TextElement* >(*it);
     208           0 :         if( pText )
     209             :         {
     210           0 :             const FontAttributes& rFont = rProc.getFont( pText->FontId );
     211           0 :             if( pText->h > rFont.size*1.5 )
     212           0 :                 return  false;
     213           0 :             if( pLastText )
     214             :             {
     215           0 :                 if( pText->y > pLastText->y+pLastText->h ||
     216           0 :                     pLastText->y > pText->y+pText->h )
     217           0 :                     return false;
     218             :             }
     219             :             else
     220           0 :                 pLastText = pText;
     221             :         }
     222           0 :         ++it;
     223             :     }
     224             : 
     225             :     // a paragraph without a single text is not considered single lined
     226           0 :     return pLastText != NULL;
     227             : }
     228             : 
     229           0 : double ParagraphElement::getLineHeight( PDFIProcessor& rProc ) const
     230             : {
     231           0 :     double line_h = 0;
     232           0 :     for( std::list< Element* >::const_iterator it = Children.begin(); it != Children.end(); ++it )
     233             :     {
     234           0 :         ParagraphElement* pPara = dynamic_cast< ParagraphElement* >(*it);
     235           0 :         TextElement* pText = NULL;
     236           0 :         if( pPara )
     237             :         {
     238           0 :             double lh = pPara->getLineHeight( rProc );
     239           0 :             if( lh > line_h )
     240           0 :                 line_h = lh;
     241             :         }
     242           0 :         else if( (pText = dynamic_cast< TextElement* >( *it )) != NULL )
     243             :         {
     244           0 :             const FontAttributes& rFont = rProc.getFont( pText->FontId );
     245           0 :             double lh = pText->h;
     246           0 :             if( pText->h > rFont.size*1.5 )
     247           0 :                 lh = rFont.size;
     248           0 :             if( lh > line_h )
     249           0 :                 line_h = lh;
     250             :         }
     251             :     }
     252           0 :     return line_h;
     253             : }
     254             : 
     255           0 : TextElement* ParagraphElement::getFirstTextChild() const
     256             : {
     257           0 :     TextElement* pText = NULL;
     258           0 :     for( std::list< Element* >::const_iterator it = Children.begin();
     259           0 :          it != Children.end() && ! pText; ++it )
     260             :     {
     261           0 :         pText = dynamic_cast<TextElement*>(*it);
     262             :     }
     263           0 :     return pText;
     264             : }
     265             : 
     266          12 : PageElement::~PageElement()
     267             : {
     268           4 :     if( HeaderElement )
     269           0 :         delete HeaderElement;
     270           4 :     if( FooterElement )
     271           0 :         delete FooterElement;
     272           8 : }
     273             : 
     274          12 : void PageElement::visitedBy( ElementTreeVisitor&                          rVisitor,
     275             :                              const std::list< Element* >::const_iterator& rParentIt )
     276             : {
     277          12 :      rVisitor.visit(*this, rParentIt);
     278          12 : }
     279             : 
     280           0 : void PageElement::updateParagraphGeometry( Element* pEle )
     281             : {
     282             :     // update geometry of children
     283           0 :     for( std::list< Element* >::iterator it = pEle->Children.begin();
     284           0 :          it != pEle->Children.end(); ++it )
     285             :     {
     286           0 :         updateParagraphGeometry( *it );
     287             :     }
     288             :     // if this is a paragraph itself, then update according to children geometry
     289           0 :     if( dynamic_cast<ParagraphElement*>(pEle) )
     290             :     {
     291           0 :         for( std::list< Element* >::iterator it = pEle->Children.begin();
     292           0 :              it != pEle->Children.end(); ++it )
     293             :         {
     294           0 :             Element* pChild = NULL;
     295           0 :             TextElement* pText = dynamic_cast<TextElement*>(*it);
     296           0 :             if( pText )
     297           0 :                 pChild = pText;
     298             :             else
     299             :             {
     300           0 :                 ParagraphElement* pPara = dynamic_cast<ParagraphElement*>(*it);
     301           0 :                 if( pPara )
     302           0 :                     pChild = pPara;
     303             :             }
     304           0 :             if( pChild )
     305           0 :                 pEle->updateGeometryWith( pChild );
     306             :         }
     307             :     }
     308           0 : }
     309             : 
     310           4 : bool PageElement::resolveHyperlink( std::list<Element*>::iterator link_it, std::list<Element*>& rElements )
     311             : {
     312           4 :     HyperlinkElement* pLink = dynamic_cast<HyperlinkElement*>(*link_it);
     313           4 :     if( ! pLink ) // sanity check
     314           0 :         return false;
     315             : 
     316          64 :     for( std::list<Element*>::iterator it = rElements.begin(); it != rElements.end(); ++it )
     317             :     {
     318         180 :         if( (*it)->x >= pLink->x && (*it)->x + (*it)->w <= pLink->x + pLink->w &&
     319          60 :             (*it)->y >= pLink->y && (*it)->y + (*it)->h <= pLink->y + pLink->h )
     320             :         {
     321           0 :             TextElement* pText = dynamic_cast<TextElement*>(*it);
     322           0 :             if( pText )
     323             :             {
     324           0 :                 if( pLink->Children.empty() )
     325             :                 {
     326             :                     // insert the hyperlink before the frame
     327           0 :                     rElements.splice( it, Hyperlinks.Children, link_it );
     328           0 :                     pLink->Parent = (*it)->Parent;
     329             :                 }
     330             :                 // move text element into hyperlink
     331           0 :                 std::list<Element*>::iterator next = it;
     332           0 :                 ++next;
     333           0 :                 Element::setParent( it, pLink );
     334           0 :                 it = next;
     335           0 :                 --it;
     336           0 :                 continue;
     337             :             }
     338             :             // a link can contain multiple text elements or a single frame
     339           0 :             if( ! pLink->Children.empty() )
     340           0 :                 continue;
     341           0 :             if( dynamic_cast<ParagraphElement*>(*it)  )
     342             :             {
     343           0 :                 if( resolveHyperlink( link_it, (*it)->Children ) )
     344           0 :                     break;
     345           0 :                 continue;
     346             :             }
     347           0 :             FrameElement* pFrame = dynamic_cast<FrameElement*>(*it);
     348           0 :             if( pFrame )
     349             :             {
     350             :                 // insert the hyperlink before the frame
     351           0 :                 rElements.splice( it, Hyperlinks.Children, link_it );
     352           0 :                 pLink->Parent = (*it)->Parent;
     353             :                 // move frame into hyperlink
     354           0 :                 Element::setParent( it, pLink );
     355           0 :                 break;
     356             :             }
     357             :         }
     358             :     }
     359           4 :     return ! pLink->Children.empty();
     360             : }
     361             : 
     362           4 : void PageElement::resolveHyperlinks()
     363             : {
     364          12 :     while( ! Hyperlinks.Children.empty() )
     365             :     {
     366           4 :         if( ! resolveHyperlink( Hyperlinks.Children.begin(), Children ) )
     367             :         {
     368           4 :             delete Hyperlinks.Children.front();
     369           4 :             Hyperlinks.Children.pop_front();
     370             :         }
     371             :     }
     372           4 : }
     373             : 
     374           4 : void PageElement::resolveFontStyles( PDFIProcessor& rProc )
     375             : {
     376           4 :     resolveUnderlines(rProc);
     377           4 : }
     378             : 
     379           4 : void PageElement::resolveUnderlines( PDFIProcessor& rProc )
     380             : {
     381             :     // FIXME: currently the algorithm used is quadratic
     382             :     // this could be solved by some sorting beforehand
     383             : 
     384           4 :     std::list< Element* >::iterator poly_it = Children.begin();
     385          68 :     while( poly_it != Children.end() )
     386             :     {
     387          60 :         PolyPolyElement* pPoly = dynamic_cast< PolyPolyElement* >(*poly_it);
     388          60 :         if( ! pPoly || ! pPoly->Children.empty() )
     389             :         {
     390          48 :             ++poly_it;
     391          48 :             continue;
     392             :         }
     393             :         /* check for: no filling
     394             :         *             only two points (FIXME: handle small rectangles, too)
     395             :         *             y coordinates of points are equal
     396             :         */
     397          12 :         if( pPoly->Action != PATH_STROKE )
     398             :         {
     399           4 :             ++poly_it;
     400           4 :             continue;
     401             :         }
     402           8 :         if( pPoly->PolyPoly.count() != 1 )
     403             :         {
     404           0 :             ++poly_it;
     405           0 :             continue;
     406             :         }
     407             : 
     408           8 :         bool bRemovePoly = false;
     409           8 :         basegfx::B2DPolygon aPoly = pPoly->PolyPoly.getB2DPolygon(0);
     410          40 :         if( aPoly.count() != 2 ||
     411          40 :             aPoly.getB2DPoint(0).getY() != aPoly.getB2DPoint(1).getY() )
     412             :         {
     413           8 :             ++poly_it;
     414           8 :             continue;
     415             :         }
     416           0 :         double l_x = aPoly.getB2DPoint(0).getX();
     417           0 :         double r_x = aPoly.getB2DPoint(1).getX();
     418             :         double u_y;
     419           0 :         if( r_x < l_x )
     420             :         {
     421           0 :             u_y = r_x; r_x = l_x; l_x = u_y;
     422             :         }
     423           0 :         u_y = aPoly.getB2DPoint(0).getY();
     424           0 :         for( std::list< Element*>::iterator it = Children.begin();
     425           0 :              it != Children.end(); ++it )
     426             :         {
     427           0 :             Element* pEle = *it;
     428           0 :             if( pEle->y <= u_y && pEle->y + pEle->h*1.1 >= u_y )
     429             :             {
     430             :                 // first: is the element underlined completely ?
     431           0 :                 if( pEle->x + pEle->w*0.1 >= l_x &&
     432           0 :                     pEle->x + pEle->w*0.9 <= r_x )
     433             :                 {
     434           0 :                     TextElement* pText = dynamic_cast< TextElement* >(pEle);
     435           0 :                     if( pText )
     436             :                     {
     437           0 :                         const GraphicsContext& rTextGC = rProc.getGraphicsContext( pText->GCId );
     438           0 :                         if( ! rTextGC.isRotatedOrSkewed() )
     439             :                         {
     440           0 :                             bRemovePoly = true;
     441             :                             // retrieve ID for modified font
     442           0 :                             FontAttributes aAttr = rProc.getFont( pText->FontId );
     443           0 :                             aAttr.isUnderline = true;
     444           0 :                             pText->FontId = rProc.getFontId( aAttr );
     445             :                         }
     446             :                     }
     447           0 :                     else if( dynamic_cast< HyperlinkElement* >(pEle) )
     448           0 :                         bRemovePoly = true;
     449             :                 }
     450             :                 // second: hyperlinks may be larger than their underline
     451             :                 // since they are just arbitrary rectangles in the action definition
     452           0 :                 else if( dynamic_cast< HyperlinkElement* >(pEle) != NULL &&
     453           0 :                          l_x >= pEle->x && r_x <= pEle->x+pEle->w )
     454             :                 {
     455           0 :                     bRemovePoly = true;
     456             :                 }
     457             :             }
     458             :         }
     459           0 :         if( bRemovePoly )
     460             :         {
     461           0 :             std::list< Element* >::iterator next_it = poly_it;
     462           0 :             ++next_it;
     463           0 :             Children.erase( poly_it );
     464           0 :             delete pPoly;
     465           0 :             poly_it = next_it;
     466             :         }
     467             :         else
     468           0 :             ++poly_it;
     469           0 :     }
     470           4 : }
     471             : 
     472           8 : DocumentElement::~DocumentElement()
     473             : {
     474           8 : }
     475             : 
     476          12 : void DocumentElement::visitedBy( ElementTreeVisitor&                          rVisitor,
     477             :                                  const std::list< Element* >::const_iterator& rParentIt)
     478             : {
     479          12 :     rVisitor.visit(*this, rParentIt);
     480          12 : }
     481             : 
     482             : 
     483             : }
     484             : 
     485             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10