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