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