Commit 4387e148 authored by Piotr Szymanski's avatar Piotr Szymanski

- GIGANTIC 2700 line diff with LOTS OF FEATURES!

- 1. editor-like text selection, and I do mean it, its not pseudo-editor 
  (like the ones acroread and kviewshell have) it doesnt intersect the 
  selection area with words under it, no, it does a lot more, including 
  work on cursors and searching for the text area closest to the given
  cursor
- 2. rotation support, change the orientation of the documents if 
  you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
  is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender 
  instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended, 
  the kviewshell is only one state, while we support it in both 
  continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
  it is an impressive bit right? but oKular cant be run by only one person, 
  join in on the fun! i can introduce you into the code just mail niedakh@gmail.com


svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
parent efd05b1e
This diff is collapsed.
...@@ -184,6 +184,11 @@ ...@@ -184,6 +184,11 @@
<min>1</min> <min>1</min>
<max>8</max> <max>8</max>
</entry> </entry>
<entry key="ViewRows" type="UInt" >
<default>1</default>
<min>1</min>
<max>5</max>
</entry>
<entry key="ViewContinuous" type="Bool" > <entry key="ViewContinuous" type="Bool" >
<default>true</default> <default>true</default>
</entry> </entry>
......
...@@ -145,10 +145,10 @@ Annotation::Annotation( const QDomNode & annNode ) ...@@ -145,10 +145,10 @@ Annotation::Annotation( const QDomNode & annNode )
// parse boundary // parse boundary
if ( ee.tagName() == "boundary" ) if ( ee.tagName() == "boundary" )
{ {
boundary.left = ee.attribute( "l" ).toDouble(); boundary=NormalizedRect(ee.attribute( "l" ).toDouble(),
boundary.top = ee.attribute( "t" ).toDouble(); ee.attribute( "t" ).toDouble(),
boundary.right = ee.attribute( "r" ).toDouble(); ee.attribute( "r" ).toDouble(),
boundary.bottom = ee.attribute( "b" ).toDouble(); ee.attribute( "b" ).toDouble());
} }
// parse penStyle if not default // parse penStyle if not default
else if ( ee.tagName() == "penStyle" ) else if ( ee.tagName() == "penStyle" )
......
...@@ -37,7 +37,7 @@ NormalizedRect::NormalizedRect( const QRect & r, double xScale, double yScale ) ...@@ -37,7 +37,7 @@ NormalizedRect::NormalizedRect( const QRect & r, double xScale, double yScale )
bool NormalizedRect::isNull() const bool NormalizedRect::isNull() const
{ {
return left == 0 && top == 0 && right == 0 && bottom == 0; return left == 0 && top== 0 && right == 0 && bottom == 0;
} }
bool NormalizedRect::contains( double x, double y ) const bool NormalizedRect::contains( double x, double y ) const
...@@ -60,6 +60,28 @@ bool NormalizedRect::intersects( double l, double t, double r, double b ) const ...@@ -60,6 +60,28 @@ bool NormalizedRect::intersects( double l, double t, double r, double b ) const
return (l <= right) && (r >= left) && (t <= bottom) && (b >= top); return (l <= right) && (r >= left) && (t <= bottom) && (b >= top);
} }
NormalizedRect NormalizedRect::operator| (const NormalizedRect & r) const
{
NormalizedRect ret;
// todo !
ret.left=QMIN(left,r.left);
ret.top=QMIN(top,r.top);
ret.bottom=QMAX(bottom,r.bottom);
ret.right=QMAX(right,r.right);
return ret;
}
NormalizedRect& NormalizedRect::operator|= (const NormalizedRect & r)
{
return ((*this) = (*this) | r );
}
/*
kdbgstream& operator << (kdbgstream& str , const NormalizedRect &r)
{
str << "[" <<r.left() << "," << r.top() << "] x "<< "[" <<r.right() << "," << r.bottom() << "]";
return str;
}*/
QRect NormalizedRect::geometry( int xScale, int yScale ) const QRect NormalizedRect::geometry( int xScale, int yScale ) const
{ {
int l = (int)( left * xScale ), int l = (int)( left * xScale ),
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#define _KPDF_AREA_H_ #define _KPDF_AREA_H_
#include <qvaluelist.h> #include <qvaluelist.h>
#include <qcolor.h> #include <qcolor.h>
#include <kdebug.h>
class QRect; class QRect;
class KPDFLink; class KPDFLink;
...@@ -44,8 +45,11 @@ class NormalizedRect ...@@ -44,8 +45,11 @@ class NormalizedRect
bool intersects( double l, double t, double r, double b ) const; bool intersects( double l, double t, double r, double b ) const;
bool intersects( const NormalizedRect * r ) const; bool intersects( const NormalizedRect * r ) const;
QRect geometry( int xScale, int yScale ) const; QRect geometry( int xScale, int yScale ) const;
NormalizedRect operator| (const NormalizedRect & r) const;
NormalizedRect& operator|= (const NormalizedRect & r);
}; };
// kdbgstream& operator << (kdbgstream &, const NormalizedRect &);
/** /**
* @short NormalizedRect that contains a reference to an object. * @short NormalizedRect that contains a reference to an object.
...@@ -98,6 +102,7 @@ struct HighlightRect : public NormalizedRect ...@@ -98,6 +102,7 @@ struct HighlightRect : public NormalizedRect
* intersects(NormalizedShape) * intersects(NormalizedShape)
* isNull() * isNull()
* geometry(int,int) * geometry(int,int)
* operator | and |= which unite two NormalizedShapes
*/ */
template <class NormalizedShape, class Shape> class RegularArea : template <class NormalizedShape, class Shape> class RegularArea :
...@@ -109,13 +114,43 @@ public QValueList<NormalizedShape*> ...@@ -109,13 +114,43 @@ public QValueList<NormalizedShape*>
// RegularArea<NormalizedShape,Shape> (NormalizedShape* x) { QValueList(x) ; } ; // RegularArea<NormalizedShape,Shape> (NormalizedShape* x) { QValueList(x) ; } ;
// class Iterator : public QValueListIterator<NormalizedShape*> {}; // class Iterator : public QValueListIterator<NormalizedShape*> {};
bool contains( double x, double y ) const; bool contains( double x, double y ) const;
bool contains( NormalizedShape * ) const;
bool intersects (const RegularArea<NormalizedShape,Shape> * area) const; bool intersects (const RegularArea<NormalizedShape,Shape> * area) const;
bool intersects (const NormalizedShape * shape) const; bool intersects (const NormalizedShape * shape) const;
void appendArea (const RegularArea<NormalizedShape,Shape> *area); void appendArea (const RegularArea<NormalizedShape,Shape> *area);
void simplify ();
bool isNull() const; bool isNull() const;
QValueList<Shape>* geometry( int xScale, int yScale ) const; QValueList<Shape>* geometry( int xScale, int yScale, int dx=0,int dy=0 ) const;
}; };
template <class NormalizedShape, class Shape>
void RegularArea<NormalizedShape, Shape>::simplify()
{
int end=this->count(),i=0,x=0;
QValueList <NormalizedShape*> m_remove;
for (;i<end;i++)
{
if ( i < (end-1) )
{
if ( (*this)[x]->intersects( (*this)[i+1] ) )
{
*((*this)[x]) |= *((*this)[i+1]);
m_remove.append( (*this)[i+1] );
}
else
{
x=i+1;
}
}
}
while (!m_remove.isEmpty())
{
this->remove( m_remove.last() );
m_remove.pop_back();
}
kdDebug() << "from " << end << " to " << this->count() << endl;
}
template <class NormalizedShape, class Shape> template <class NormalizedShape, class Shape>
bool RegularArea<NormalizedShape, Shape>::isNull() const bool RegularArea<NormalizedShape, Shape>::isNull() const
{ {
...@@ -204,9 +239,21 @@ bool RegularArea<NormalizedShape, Shape>::contains (double x, double y) const ...@@ -204,9 +239,21 @@ bool RegularArea<NormalizedShape, Shape>::contains (double x, double y) const
return false; return false;
} }
template <class NormalizedShape, class Shape>
bool RegularArea<NormalizedShape, Shape>::contains (NormalizedShape * shape) const
{
if (!this)
return false;
if (this->isEmpty())
return false;
const QValueList<NormalizedShape*> * const lista=dynamic_cast<const QValueList<NormalizedShape*> * const >(this);
return lista->contains(shape);
}
template <class NormalizedShape, class Shape> template <class NormalizedShape, class Shape>
QValueList<Shape> * QValueList<Shape> *
RegularArea<NormalizedShape, Shape>::geometry( int xScale, int yScale ) const RegularArea<NormalizedShape, Shape>::geometry( int xScale, int yScale, int dx, int dy ) const
{ {
if (!this) if (!this)
return false; return false;
...@@ -214,11 +261,13 @@ RegularArea<NormalizedShape, Shape>::geometry( int xScale, int yScale ) const ...@@ -214,11 +261,13 @@ RegularArea<NormalizedShape, Shape>::geometry( int xScale, int yScale ) const
return 0; return 0;
ConstIterator i; ConstIterator i;
QValueList<Shape>* ret=0; QValueList<Shape>* ret=new QValueList<Shape>;
Shape t;
for (i=this->begin();i!=this->end();++i) for (i=this->begin();i!=this->end();++i)
{ {
ret.append((*i)->geometry(xScale,yScale)); t=(*i)->geometry(xScale,yScale);
t.moveBy(dx,dy);
ret->append(t);
} }
return ret; return ret;
......
...@@ -526,6 +526,16 @@ bool KPDFDocument::supportsRotation() const ...@@ -526,6 +526,16 @@ bool KPDFDocument::supportsRotation() const
return generator ? generator->supportsRotation() : false; return generator ? generator->supportsRotation() : false;
} }
bool KPDFDocument::supportsPaperSizes() const
{
return generator ? generator->supportsPaperSizes() : false;
}
QStringList KPDFDocument::paperSizes() const
{
return generator ? generator->paperSizes() : QStringList();
}
bool KPDFDocument::historyAtBegin() const bool KPDFDocument::historyAtBegin() const
{ {
return d->viewportIterator == d->viewportHistory.begin(); return d->viewportIterator == d->viewportHistory.begin();
...@@ -575,6 +585,7 @@ void KPDFDocument::requestPixmaps( const QValueList< PixmapRequest * > & request ...@@ -575,6 +585,7 @@ void KPDFDocument::requestPixmaps( const QValueList< PixmapRequest * > & request
{ {
// set the 'page field' (see PixmapRequest) and check if it is valid // set the 'page field' (see PixmapRequest) and check if it is valid
PixmapRequest * request = *rIt; PixmapRequest * request = *rIt;
kdWarning() << "request id=" << request->id << " " <<request->width << "x" << request->height << "@" << request->pageNumber << endl;
if ( !(request->page = pages_vector[ request->pageNumber ]) ) if ( !(request->page = pages_vector[ request->pageNumber ]) )
{ {
// skip requests referencing an invalid page (must not happen) // skip requests referencing an invalid page (must not happen)
...@@ -1294,6 +1305,7 @@ void KPDFDocument::sendGeneratorRequest() ...@@ -1294,6 +1305,7 @@ void KPDFDocument::sendGeneratorRequest()
// submit the request to the generator // submit the request to the generator
if ( generator->canGeneratePixmap( request->async ) ) if ( generator->canGeneratePixmap( request->async ) )
{ {
kdWarning() << "sending request id=" << request->id << " " <<request->width << "x" << request->height << "@" << request->pageNumber << " async == " << request->async << endl;
d->pixmapRequestsStack.remove ( request ); d->pixmapRequestsStack.remove ( request );
generator->generatePixmap ( request ); generator->generatePixmap ( request );
} }
...@@ -1593,14 +1605,27 @@ void KPDFDocument::slotTimedMemoryCheck() ...@@ -1593,14 +1605,27 @@ void KPDFDocument::slotTimedMemoryCheck()
void KPDFDocument::slotOrientation( int orientation ) void KPDFDocument::slotOrientation( int orientation )
{ {
if (generator->supportsRotation()) if ( generator->supportsRotation() )
{ {
generator->setOrientation(pages_vector,orientation); generator->setOrientation(pages_vector,orientation);
foreachObserver( notifySetup( pages_vector, true ) ); foreachObserver( notifySetup( pages_vector, true ) );
foreachObserver( notifyContentsCleared (DocumentObserver::Pixmap | DocumentObserver::Highlights | DocumentObserver::Annotations));
// foreachObserver( notifyViewportChanged( false /*disables smoothMove*/ ));
// foreachObserver( notifyPageChanged( ) );
kdDebug() << "Oreint: " << orientation << endl; kdDebug() << "Oreint: " << orientation << endl;
} }
} }
void KPDFDocument::slotPaperSizes( int newsize )
{
if (generator->supportsPaperSizes())
{
generator->setPaperSize(pages_vector,newsize);
foreachObserver( notifySetup( pages_vector, true ) );
kdDebug() << "PaperSize no: " << newsize << endl;
}
}
/** DocumentViewport **/ /** DocumentViewport **/
DocumentViewport::DocumentViewport( int n ) DocumentViewport::DocumentViewport( int n )
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <qobject.h> #include <qobject.h>
#include <qvaluevector.h> #include <qvaluevector.h>
#include <qstring.h> #include <qstring.h>
#include <qstringlist.h>
#include <qdom.h> #include <qdom.h>
#include <qdict.h> #include <qdict.h>
#include <kmimetype.h> #include <kmimetype.h>
...@@ -86,6 +87,8 @@ class KPDFDocument : public QObject ...@@ -86,6 +87,8 @@ class KPDFDocument : public QObject
bool isAllowed( int /*Document::Permisison(s)*/ ) const; bool isAllowed( int /*Document::Permisison(s)*/ ) const;
bool supportsSearching() const; bool supportsSearching() const;
bool supportsRotation() const; bool supportsRotation() const;
bool supportsPaperSizes() const;
QStringList paperSizes() const;
// might be useful later // might be useful later
// bool hasFonts() const; // bool hasFonts() const;
bool historyAtBegin() const; bool historyAtBegin() const;
...@@ -122,6 +125,7 @@ class KPDFDocument : public QObject ...@@ -122,6 +125,7 @@ class KPDFDocument : public QObject
public slots: public slots:
void slotOrientation( int orientation ); void slotOrientation( int orientation );
void slotPaperSizes( int );
signals: signals:
void close(); void close();
......
...@@ -85,6 +85,9 @@ class Generator : public QObject ...@@ -85,6 +85,9 @@ class Generator : public QObject
// rotation // rotation
virtual bool supportsRotation() { return false; }; virtual bool supportsRotation() { return false; };
virtual void setOrientation(QValueVector<KPDFPage*> & /*pagesVector*/, int /*orientation*/) { ; }; virtual void setOrientation(QValueVector<KPDFPage*> & /*pagesVector*/, int /*orientation*/) { ; };
virtual bool supportsPaperSizes () { return false; }
virtual QStringList paperSizes () { return QStringList(); }
virtual void setPaperSize (QValueVector<KPDFPage*> & /*pagesVector*/, int /*newsize*/) { ; }
// internal search and gettext // internal search and gettext
virtual RegularAreaRect * findText( const QString & /*text*/, SearchDir /*dir*/, const bool /*strictCase*/, virtual RegularAreaRect * findText( const QString & /*text*/, SearchDir /*dir*/, const bool /*strictCase*/,
......
#ifndef _KPDF_MISC_H_
#define _KPDF_MISC_H_
#include "area.h"
/**
@short Wrapper around the information needed to generate the selection area
There are two assumptions inside this class:
1. the start never changes, one instance of this class is used for one selection,
therefore the start of the selection will not change, only end and direction of
the selection will change.
By direction we mean the direction in which the end moves in relation to the start,
forward selection is when end is after the start, backward when its before.
2. The following changes might appear during selection:
a. the end moves without changing the direction (it can move up and down but not past the start):
only itE will be updated
b. the end moves with changing the direction then itB becomes itE if the previous direction was forward
or itE becomes itB
3. Internally it that is related to the start cursor is always at it[0] while it related to end is it[1],
transition between meanings (itB/itE) is done with dir modifier;
*/
class TextSelection
{
public:
TextSelection (NormalizedPoint &a, NormalizedPoint &b)
{
if (b.y-a.y<0 || (b.y-a.y==0 && b.x-a.x <0))
direction=1;
else
direction=0;
cur[0]=a,cur[1]=b;
it[direction%2]=-1,it[(direction+1)%2]=-1;
};
void end (NormalizedPoint & p)
{
// changing direction as in 2b , assuming the bool->int conversion is correct
int dir1=direction;
direction = (p.y-cur[0].y<0 || (p.y-cur[0].y==0 && p.x-cur[0].x <0));
if (direction!=dir1)
kdDebug() << "changing direction in selection\n";
cur[1]=p;
}
void itE (int p) { it[(direction+1)%2]=p; }
void itB (int p) { it[(direction)%2]=p; }
int dir () { return direction; }
const NormalizedPoint * start() {return &cur[direction%2];};
const NormalizedPoint * end() {return &cur[(direction+1)%2];};
int itB() {return it[direction%2];}
int itE() {return it[(direction+1)%2];}
private:
int direction;
int it[2];
NormalizedPoint cur[2];
};
#endif
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
// temp includes // temp includes
#include <sys/time.h> #include <sys/time.h>
class TextSelection;
/** class KPDFPage **/ /** class KPDFPage **/
...@@ -75,6 +75,13 @@ bool KPDFPage::hasBookmark() const ...@@ -75,6 +75,13 @@ bool KPDFPage::hasBookmark() const
return m_bookmarked; return m_bookmarked;
} }
RegularAreaRect * KPDFPage::getTextArea ( TextSelection * sel ) const
{
if (m_text)
return m_text->getTextArea (sel);
return 0;
}
bool KPDFPage::hasObjectRect( double x, double y ) const bool KPDFPage::hasObjectRect( double x, double y ) const
{ {
if ( m_rects.count() < 1 ) if ( m_rects.count() < 1 )
......
...@@ -21,7 +21,7 @@ class QDomDocument; ...@@ -21,7 +21,7 @@ class QDomDocument;
class KPDFPageTransition; class KPDFPageTransition;
class Annotation; class Annotation;
class KPDFTextPage; class KPDFTextPage;
class TextSelection;
// didnt work with forward declarations // didnt work with forward declarations
#include "area.h" #include "area.h"
#include "textpage.h" #include "textpage.h"
...@@ -34,6 +34,7 @@ class HighlightAreaRect; ...@@ -34,6 +34,7 @@ class HighlightAreaRect;
class ObjectRect; class ObjectRect;
*/ */
/** /**
* @short Collector for all the data belonging to a page. * @short Collector for all the data belonging to a page.
* *
...@@ -68,6 +69,7 @@ class KPDFPage ...@@ -68,6 +69,7 @@ class KPDFPage
RegularAreaRect * findText( const QString & text, SearchDir dir, bool strictCase, const RegularAreaRect * lastRect=0) const; RegularAreaRect * findText( const QString & text, SearchDir dir, bool strictCase, const RegularAreaRect * lastRect=0) const;
QString * getText( const RegularAreaRect * rect ) const; QString * getText( const RegularAreaRect * rect ) const;
RegularAreaRect * getTextArea ( TextSelection * ) const;
// const ObjectRect * getObjectRect( double x, double y ) const; // const ObjectRect * getObjectRect( double x, double y ) const;
const ObjectRect * getObjectRect( ObjectRect::ObjectType type, double x, double y ) const; const ObjectRect * getObjectRect( ObjectRect::ObjectType type, double x, double y ) const;
//const Annotation * getAnnotation( double x, double y ) const; //const Annotation * getAnnotation( double x, double y ) const;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
***************************************************************************/ ***************************************************************************/
#include "textpage.h" #include "textpage.h"
#include "area.h" #include "area.h"
#include "misc.h"
#include <kdebug.h> #include <kdebug.h>
KPDFTextPage::~KPDFTextPage() KPDFTextPage::~KPDFTextPage()
...@@ -19,6 +20,122 @@ KPDFTextPage::~KPDFTextPage() ...@@ -19,6 +20,122 @@ KPDFTextPage::~KPDFTextPage()
} }
} }
RegularAreaRect * KPDFTextPage::getTextArea ( TextSelection * sel) const
{
/**
It works like this:
There are two cursors, we need to select all the text between them. The coordinates are normalised, leftTop is (0,0)
rightBottom is (1,1), so for cursors start (sx,sy) and end (ex,ey) we start with finding text rectangles under those
points, if not we search for the first that is to the right to it in the same baseline, if none found, then we search
for the first rectangle with a baseline under the cursor, having two points that are the best rectangles to both
of the cursors: (rx,ry)x(tx,ty) for start and (ux,uy)x(vx,vy) for end, we do a
1. (rx,ry)x(1,ty)
2. (0,ty)x(1,uy)
3. (0,uy)x(vx,vy)
To find the closest rectangle to cursor (cx,cy) we search for a rectangle that either contains the cursor
or that has a left border >= cx and bottom border >= cy.
*/
RegularAreaRect * ret= new RegularAreaRect;
int it=-1,itB=-1,itE=-1;
// if (sel->itB==-1)
// ending cursor is higher then start cursor, we need to find positions in reverse
NormalizedRect *tmp=0,*start=0,*end=0;
const NormalizedPoint * startC=sel->start();
const NormalizedPoint * endC=sel->end();
if (sel->dir() == 1 || (sel->itB()==-1 && sel->dir()==0))
{
kdWarning() << "running first loop\n";
for (it=0;it<m_words.count();it++)
{
tmp=m_words[it]->area;
if (tmp->contains(startC->x,startC->y)
|| ( tmp->top <= startC->y && tmp->bottom >= startC->y && tmp->left >= startC->x )
|| ( tmp->top >= startC->y))
{
/// we have found the (rx,ry)x(tx,ty)
itB=it;
kdWarning() << "start is " << itB << " count is " << m_words.count() << endl;
break;
}
}
sel->itB(itB);
}
itB=sel->itB();
kdWarning() << "direction is " << sel->dir() << endl;
kdWarning() << "reloaded start is " << itB << " against " << sel->itB() << endl;
if (sel->dir() == 0 || (sel->itE() == -1 && sel->dir()==1))
{
kdWarning() << "running second loop\n";
for (it=m_words.count()-1; it>=itB;it--)
{
tmp=m_words[it]->area;
if (tmp->contains(endC->x,endC->y)
|| ( tmp->top <= endC->y && tmp->bottom >= endC->y && tmp->right <= endC->x )
|| ( tmp->bottom <= endC->y))
{
/// we have found the (ux,uy)x(vx,vy)
itE=it;
kdWarning() << "ending is " << itE << " count is " << m_words.count() << endl;
kdWarning () << "conditions " << tmp->contains(endC->x,endC->y) << " "
<< ( tmp->top <= endC->y && tmp->bottom >= endC->y && tmp->right <= endC->x ) << " " <<
( tmp->top >= endC->y) << endl;
break;
}
}
sel->itE(itE);
}
kdWarning() << "reloaded ending is " << itE << " against " << sel->itE() << endl;
if (sel->itB()!=-1 && sel->itE()!=-1)
{
start=m_words[sel->itB()]->area;
end=m_words[sel->itE()]->area;
NormalizedRect first,second,third;/*
first.right=1;
/// if (rx,ry)x(1,ty) intersects the end cursor, there is only one line
bool sameBaseline=end->intersects(first);
kdWarning() << "sameBaseline : " << sameBaseline << endl;
if (sameBaseline)
{
first=*start;
first.right=end->right;
first.bottom=end->bottom;
for (it=QMIN(sel->itB(),sel->itE()); it<=QMAX(sel->itB(),sel->itE());it++)
{
tmp=m_words[it]->area;
if (tmp->intersects(&first))
ret->append(tmp);
}
}
else*/
/// finding out if there are more then one baseline between them is a hard and discussable task
/// we will create a rectangle (rx,0)x(tx,1) and will check how many times does it intersect the
/// areas, if more than one -> we have a three or over line selection
// {
first=*start;
second.top=start->bottom;
first.right=second.right=1;
third=*end;
third.left=second.left=0;
second.bottom=end->top;
for (it=QMIN(sel->itB(),sel->itE()); it<=QMAX(sel->itB(),sel->itE());it++)
{
tmp=m_words[it]->area;
if (tmp->intersects(&first) || tmp->intersects(&second) || tmp->intersects(&third))
ret->append(tmp);
}
// }
}