File indexing completed on 2024-04-28 04:32:37

0001 /*
0002     SPDX-FileCopyrightText: 2004-05 Enrico Ros <eros.kde@email.it>
0003     SPDX-FileCopyrightText: 2005 Piotr Szymanski <niedakh@gmail.com>
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #ifndef _OKULAR_AREA_H_
0008 #define _OKULAR_AREA_H_
0009 
0010 #include <math.h>
0011 
0012 #include <QColor>
0013 #include <QDebug>
0014 #include <QList>
0015 #include <QPainterPath>
0016 #include <QTransform>
0017 
0018 #include "global.h"
0019 #include "okularcore_export.h"
0020 
0021 class QPolygonF;
0022 class QRect;
0023 
0024 namespace Okular
0025 {
0026 class Annotation;
0027 class Action;
0028 class NormalizedShape;
0029 
0030 /**
0031  * NormalizedPoint is a helper class which stores the coordinates
0032  * of a normalized point.
0033  *
0034  * @par Normalized Coordinate System
0035  * @parblock
0036  * Normalized means that the coordinates are always between 0 and 1,
0037  * unless the point shall be outside of the reference area.
0038  *
0039  * The reference area is a rectangle, and all normalized points
0040  * with coordinates of 0 or 1 describe its edges.
0041  *
0042  * This allows to locate things on a reference area without knowing its
0043  * (current or future) actual size. When the reference area is resized,
0044  * all things which are described in normalized coordinates keep their
0045  * proportional position on the area.
0046  * @endparblock
0047  *
0048  * @par Transformation to and from Normalized Coordinates
0049  * @parblock
0050  * To transform normalized coordinates to coordinates on the reference area,
0051  * just multiply them with the size of the reference area.
0052  *
0053  * To get normalized coordinates from a point on the reference area,
0054  * just divide its coordinates with the size of the reference area.
0055  *
0056  * Many methods have parameters @c xScale and @c yScale,
0057  * these are equal to the size of the reference area.
0058  * @endparblock
0059  *
0060  * @par Normalized Coordinate System Applied to Pages
0061  * @parblock
0062  * Okular uses a normalized coordinate system mainly to describe
0063  * positions on pages.
0064  * This is useful because pages can be shown in different sizes (zoom),
0065  * but all objects shall keep their proportional position on the page.
0066  *
0067  * Okular maps from page to normalized coordinates as follows:
0068  *  * Left edge of the page: x = 0
0069  *  * Right edge of the page: x = 1
0070  *  * Top edge of the page: y = 0
0071  *  * Bottom edge of the page: y = 1
0072  * @endparblock
0073  *
0074  * @par Example: Draw a Point on a Page
0075  * @parblock
0076  * The point is given in normalized coordinates (0.5, 0.3).
0077  *
0078  * If you want to draw it on a 800x600 page,
0079  * just multiply the x coordinate (0.5) with the page width (800),
0080  * and the y coordinate (0.3) with the page height (600).
0081  * So, the point will be drawn on the page at (400, 180).
0082  *
0083  * That allows you to zoom the page by just multiplying the normalized points with the
0084  * zoomed page size.
0085  * @endparblock
0086  *
0087  * @par Example: Select Text on a Page using Mouse Events
0088  * @parblock
0089  * The position of all glyphs and words is stored in normalized coordinates.
0090  * (This is what TextPage actually does.)
0091  * Mouse press and release events are given in page coordinates (400, 180) and (600, 450),
0092  * while the page has a size of 800x600.
0093  *
0094  * If you want to search all text between the mouse click and release event,
0095  * you need their normalized coordinates.
0096  * Just divide the x coordinates (400 and 600) by the page width (800),
0097  * and the y coordinates (180 and 450) by the page height (600).
0098  * So, you have to search for all glyphs between (0.5, 0.3) and (0.75, 0.75).
0099  *
0100  * That allows you to process all glyphs and words without
0101  * having to keep any of their positions in sync with the page.
0102  * @endparblock
0103  *
0104  * @par Geometric operations
0105  * @parblock
0106  * NormalizedPoint supports basic geometric operations.
0107  *  * You can transform it with a QTransform matrix.
0108  *  * With the size of the reference area, you can calculate the squared
0109  *    absolute distance to another NormalizedPoint or a line of two NormalizedPoints.
0110  *
0111  * NormalizedRect provides additional geometric operations for rectangles.
0112  * @endparblock
0113  *
0114  * @see NormalizedRect
0115  */
0116 class OKULARCORE_EXPORT NormalizedPoint
0117 {
0118 public:
0119     /**
0120      * Creates a normalized point at (0, 0).
0121      */
0122     NormalizedPoint();
0123 
0124     /**
0125      * Creates a new normalized point with the normalized coordinates (@p x, @p y ).
0126      */
0127     NormalizedPoint(double x, double y);
0128 
0129     /**
0130      * Creates a new normalized point from an absolute point (@p x, @p y)
0131      * on a reference area of size @p xScale x @p yScale.
0132      */
0133     NormalizedPoint(int x, int y, int xScale, int yScale);
0134 
0135     /**
0136      * @internal
0137      */
0138     NormalizedPoint &operator=(const NormalizedPoint &);
0139 
0140     NormalizedPoint(const NormalizedPoint &);
0141     ~NormalizedPoint() = default;
0142 
0143     /**
0144      * Transforms the normalized point with the operations defined by @p matrix.
0145      */
0146     void transform(const QTransform &matrix);
0147 
0148     /**
0149      * Returns squared distance to normalized point (@p x, @p y)
0150      * on a reference area of size @p xScale x @p yScale.
0151      * @since 0.17 (KDE 4.11)
0152      */
0153     double distanceSqr(double x, double y, double xScale, double yScale) const;
0154 
0155     /**
0156      * Returns squared distance of the normalized point (@p x, @p y)
0157      * to the line segment from @p start to @p end
0158      * on a reference area of size @p xScale x @p yScale.
0159      * @since 0.17 (KDE 4.11)
0160      */
0161     static double distanceSqr(double x, double y, double xScale, double yScale, const NormalizedPoint &start, const NormalizedPoint &end);
0162 
0163     /**
0164      * The normalized x coordinate.
0165      */
0166     double x;
0167 
0168     /**
0169      * The normalized y coordinate.
0170      */
0171     double y;
0172 };
0173 
0174 /**
0175  * A NormalizedRect is a rectangle which can be defined by two NormalizedPoints.
0176  *
0177  * It describes a rectangular area on a reference area of undefined size.
0178  * For more information about the normalized coordinate system, see NormalizedPoint.
0179  *
0180  * In Okular, NormalizedRect can be used e. g. to describe bounding boxes of TextEntity objects,
0181  * and the highlight area of text selections.
0182  *
0183  * If you need to describe an area which consists of multiple rectangles,
0184  * you can use RegularAreaRect instead.
0185  *
0186  * @see NormalizedPoint, RegularAreaRect, TextEntity
0187  */
0188 class OKULARCORE_EXPORT NormalizedRect
0189 {
0190 public:
0191     /**
0192      * Creates a null normalized rectangle.
0193      * @see isNull()
0194      */
0195     NormalizedRect();
0196 
0197     /**
0198      * Creates a normalized rectangle with the normalized coordinates
0199      * @p left, @p top, @p right, @p bottom.
0200      *
0201      * If you need the x, y, width and height coordinates use the
0202      * following formulas:
0203      *
0204      * @li x = left
0205      * @li y = top
0206      * @li width = right - left
0207      * @li height = bottom - top
0208      *
0209      * @note
0210      * The coordinates for @p left and @p top should be lower than
0211      * @p right and @p bottom, respectively.
0212      * At negative width or height the behaviour of some operations is undefined.
0213      */
0214     NormalizedRect(double left, double top, double right, double bottom);
0215 
0216     /**
0217      * Creates a normalized rectangle from the given @p rectangle
0218      * on a reference area of size @p xScale x @p yScale.
0219      *
0220      * @note
0221      * The rectangle should have positive width and height.
0222      * You can use e. g. QRect::normalize() to ensure this.
0223      * At negative width or height the behaviour of some operations is undefined.
0224      */
0225     NormalizedRect(const QRect rectangle, double xScale, double yScale);
0226 
0227     /**
0228      * @internal
0229      */
0230     NormalizedRect(const NormalizedRect &);
0231 
0232     /**
0233      * @internal
0234      */
0235     NormalizedRect &operator=(const NormalizedRect &other);
0236 
0237     ~NormalizedRect() = default;
0238 
0239     /**
0240      * Build a normalized rect from a QRectF, which already has normalized coordinates.
0241      */
0242     static NormalizedRect fromQRectF(const QRectF &rect);
0243 
0244     /**
0245      * Returns whether this normalized rectangle is a null normalized rect.
0246      */
0247     bool isNull() const;
0248 
0249     /**
0250      * Returns whether the normalized rectangle contains the normalized point
0251      * (@p x, @p y).
0252      */
0253     bool contains(double x, double y) const;
0254 
0255     /**
0256      * Returns whether the normalized rectangle intersects the @p other normalized
0257      * rectangle.
0258      */
0259     bool intersects(const NormalizedRect &other) const;
0260 
0261     /**
0262      * This is an overloaded member function, provided for convenience. It behaves essentially
0263      * like the above function.
0264      */
0265     bool intersects(const NormalizedRect *other) const;
0266 
0267     /**
0268      * Returns whether the normalized rectangle intersects an other normalized
0269      * rectangle, which is defined by @p left, @p top, @p right and @p bottom.
0270      */
0271     bool intersects(double left, double top, double right, double bottom) const;
0272 
0273     /**
0274      * Returns the rectangle mapped to a reference area of @p xScale x @p yScale.
0275      */
0276     QRect geometry(int xScale, int yScale) const;
0277 
0278     /**
0279      * Same functionality as geometry, but the output is now rounded before typecasting to int
0280      *
0281      * @since 0.14 (KDE 4.8)
0282      */
0283     QRect roundedGeometry(int xScale, int yScale) const;
0284 
0285     /**
0286      * Same functionality as geometry, but nothing is converted into int.
0287      */
0288     QRectF geometryF(float xScale, float yScale) const;
0289 
0290     /**
0291      * Returns the normalized bounding rectangle of the normalized rectangle
0292      * combined with the @p other normalized rectangle.
0293      */
0294     NormalizedRect operator|(const NormalizedRect &other) const;
0295 
0296     /**
0297      * Sets the normalized rectangle to the normalized bounding rectangle
0298      * of itself combined with the @p other normalized rectangle.
0299      */
0300     NormalizedRect &operator|=(const NormalizedRect &other);
0301 
0302     /**
0303      * Returns the intersection of this normalized rectangle with the specified
0304      * @p other. If the rects do not intersect then the result is a null rectangle.
0305      *
0306      * @since 0.7 (KDE 4.1)
0307      */
0308     NormalizedRect operator&(const NormalizedRect &other) const;
0309 
0310     /**
0311      * Returns whether the normalized rectangle is equal to the @p other
0312      * normalized rectangle.
0313      */
0314     bool operator==(const NormalizedRect &other) const;
0315 
0316     /**
0317      * Returns the center of the rectangle
0318      * @since 0.10 (KDE 4.4)
0319      */
0320     NormalizedPoint center() const;
0321 
0322     /**
0323      * Transforms the normalized rectangle with the operations defined by @p matrix.
0324      */
0325     void transform(const QTransform &matrix);
0326 
0327     /**
0328      * Returns true if the point @p pt is located below the bottom of the rectangle
0329      * @since 0.14 (KDE 4.8)
0330      */
0331     bool isBottom(const NormalizedPoint &pt) const
0332     {
0333         return bottom < pt.y;
0334     }
0335 
0336     /**
0337      * Returns true if the point @p pt is located above the top of the rectangle
0338      * @since 0.14 (KDE 4.8)
0339      */
0340     bool isTop(const NormalizedPoint &pt) const
0341     {
0342         return top > pt.y;
0343     }
0344 
0345     /**
0346      * Returns true if the point @p pt is located below the top of the rectangle
0347      * @since 0.14 (KDE 4.8)
0348      */
0349     bool isBottomOrLevel(const NormalizedPoint &pt) const
0350     {
0351         return top < pt.y;
0352     }
0353 
0354     /**
0355      * Returns true if the point @p pt is located above the bottom of the rectangle
0356      * @since 0.14 (KDE 4.8)
0357      */
0358     bool isTopOrLevel(const NormalizedPoint &pt) const
0359     {
0360         return bottom > pt.y;
0361     }
0362 
0363     /**
0364      * Returns true if the point @p pt is located to the right of the left edge of the rectangle
0365      * @since 0.14 (KDE 4.8)
0366      */
0367     bool isLeft(const NormalizedPoint &pt) const
0368     {
0369         return left < pt.x;
0370     }
0371 
0372     /**
0373      * Returns true if the point @p pt is located to the left of the right edge of the rectangle
0374      * @since 0.14 (KDE 4.8)
0375      */
0376     bool isRight(const NormalizedPoint &pt) const
0377     {
0378         return right > pt.x;
0379     }
0380 
0381     /**
0382      * Returns the squared distance of the normalized point (@p x, @p y)
0383      * to the closest edge, or 0 if the point is within the rectangle;
0384      * using a reference area of size @p xScale x @p yScale
0385      * @since 0.17 (KDE 4.11)
0386      */
0387     double distanceSqr(double x, double y, double xScale, double yScale) const
0388     {
0389         double distX = 0;
0390         if (x < left) {
0391             distX = left - x;
0392         } else if (x > right) {
0393             distX = x - right;
0394         }
0395 
0396         double distY = 0;
0397         if (top > y) {
0398             distY = top - y;
0399         } else if (bottom < y) {
0400             distY = y - bottom;
0401         }
0402         return pow(distX * xScale, 2) + pow(distY * yScale, 2);
0403     }
0404 
0405     /// @since 1.4
0406     double width() const
0407     {
0408         return right - left;
0409     }
0410 
0411     /// @since 1.4
0412     double height() const
0413     {
0414         return bottom - top;
0415     }
0416 
0417     /**
0418      * The normalized left coordinate.
0419      */
0420     double left;
0421 
0422     /**
0423      * The normalized top coordinate.
0424      */
0425     double top;
0426 
0427     /**
0428      * The normalized right coordinate.
0429      */
0430     double right;
0431 
0432     /**
0433      * The normalized bottom coordinate.
0434      */
0435     double bottom;
0436 };
0437 // KDE_DUMMY_QHASH_FUNCTION(NormalizedRect)
0438 
0439 /**
0440  * @short An area with normalized coordinates that contains a reference to an object.
0441  *
0442  * These areas ("rects") contain a pointer to a document object
0443  * (such as a hyperlink, an action, or something like that).
0444  * The pointer is read and stored as 'void pointer' so cast is
0445  * performed by accessors based on the value returned by objectType(). Objects
0446  * are reparented to this class.
0447  *
0448  * Type / Class correspondence tab:
0449  *  - Action    : class Action: description of an action
0450  *  - Image     : class Image : description of an image (n/a)
0451  *  - Annotation: class Annotation: description of an annotation
0452  *
0453  * For more information about the normalized coordinate system, see NormalizedPoint.
0454  *
0455  * @see NormalizedPoint
0456  */
0457 class OKULARCORE_EXPORT ObjectRect
0458 {
0459 public:
0460     /**
0461      * Describes the type of storable object.
0462      */
0463     enum ObjectType {
0464         Action,      ///< An action
0465         Image,       ///< An image
0466         OAnnotation, ///< An annotation
0467         SourceRef    ///< A source reference
0468     };
0469 
0470     /**
0471      * Creates a new object rectangle.
0472      *
0473      * @param left The left coordinate of the rectangle.
0474      * @param top The top coordinate of the rectangle.
0475      * @param right The right coordinate of the rectangle.
0476      * @param bottom The bottom coordinate of the rectangle.
0477      * @param ellipse If true the rectangle describes an ellipse.
0478      * @param type The type of the storable object @see ObjectType.
0479      * @param object The pointer to the storable object.
0480      */
0481     ObjectRect(double left, double top, double right, double bottom, bool ellipse, ObjectType type, void *object);
0482 
0483     /**
0484      * This is an overloaded member function, provided for convenience.
0485      */
0486     ObjectRect(const NormalizedRect &r, bool ellipse, ObjectType type, void *object);
0487 
0488     /**
0489      * This is an overloaded member function, provided for convenience.
0490      */
0491     ObjectRect(const QPolygonF &poly, ObjectType type, void *object);
0492 
0493     /**
0494      * Destroys the object rectangle.
0495      */
0496     virtual ~ObjectRect();
0497 
0498     ObjectRect(const ObjectRect &o) = delete;
0499     ObjectRect &operator=(const ObjectRect &o) = delete;
0500 
0501     /**
0502      * Returns the object type of the object rectangle.
0503      * @see ObjectType
0504      */
0505     ObjectType objectType() const;
0506 
0507     /**
0508      * Returns the storable object of the object rectangle.
0509      */
0510     const void *object() const;
0511 
0512     /**
0513      * Returns the region that is covered by the object rectangle.
0514      */
0515     const QPainterPath &region() const;
0516 
0517     /**
0518      * Returns the bounding rect of the object rectangle for the
0519      * scaling factor @p xScale and @p yScale.
0520      */
0521     virtual QRect boundingRect(double xScale, double yScale) const;
0522 
0523     /**
0524      * Returns whether the object rectangle contains the point with absolute coordinates
0525      * (@p x, @p y) at a page size of @p xScale x @p yScale.
0526      */
0527     virtual bool contains(double x, double y, double xScale, double yScale) const;
0528 
0529     /**
0530      * Transforms the object rectangle with the operations defined by @p matrix.
0531      */
0532     virtual void transform(const QTransform &matrix);
0533 
0534     /**
0535      * Returns the squared distance between the object
0536      * and the point with
0537      * normalized coordinates (@p x, @p y)
0538      * at a page size of @p xScale x @p yScale.
0539      *
0540      * @since 0.8.2 (KDE 4.2.2)
0541      */
0542     // FIXME this should most probably be a virtual method
0543     double distanceSqr(double x, double y, double xScale, double yScale) const;
0544 
0545 protected:
0546     ObjectType m_objectType;
0547     void *m_object;
0548     QPainterPath m_path;
0549     QPainterPath m_transformedPath;
0550 };
0551 
0552 /**
0553  * This class describes the object rectangle for an annotation.
0554  */
0555 class OKULARCORE_EXPORT AnnotationObjectRect : public ObjectRect
0556 {
0557 public:
0558     /**
0559      * Creates a new annotation object rectangle with the
0560      * given @p annotation.
0561      */
0562     explicit AnnotationObjectRect(Annotation *annotation);
0563 
0564     /**
0565      * Destroys the annotation object rectangle.
0566      */
0567     ~AnnotationObjectRect() override;
0568 
0569     /**
0570      * Returns the annotation object of the annotation object rectangle.
0571      */
0572     Annotation *annotation() const;
0573 
0574     /**
0575      * Returns the bounding rect of the annotation object rectangle for the
0576      * scaling factor @p xScale and @p yScale.
0577      */
0578     QRect boundingRect(double xScale, double yScale) const override;
0579 
0580     /**
0581      * Returns whether the annotation object rectangle contains the point @p x, @p y for the
0582      * scaling factor @p xScale and @p yScale.
0583      */
0584     bool contains(double x, double y, double xScale, double yScale) const override;
0585 
0586     /**
0587      * Transforms the annotation object rectangle with the operations defined by @p matrix.
0588      */
0589     void transform(const QTransform &matrix) override;
0590 
0591 private:
0592     Annotation *m_annotation;
0593 };
0594 
0595 /**
0596  * This class describes the object rectangle for a source reference.
0597  */
0598 class OKULARCORE_EXPORT SourceRefObjectRect : public ObjectRect
0599 {
0600     friend class ObjectRect;
0601 
0602 public:
0603     /**
0604      * Creates a new source reference object rectangle.
0605      *
0606      * @param point The point of the source reference.
0607      * @param srcRef The storable source reference object.
0608      */
0609     SourceRefObjectRect(const NormalizedPoint &point, void *srcRef);
0610 
0611     /**
0612      * Returns the bounding rect of the source reference object rectangle for the
0613      * scaling factor @p xScale and @p yScale.
0614      */
0615     QRect boundingRect(double xScale, double yScale) const override;
0616 
0617     /**
0618      * Returns whether the source reference object rectangle contains the point @p x, @p y for the
0619      * scaling factor @p xScale and @p yScale.
0620      */
0621     bool contains(double x, double y, double xScale, double yScale) const override;
0622 
0623 private:
0624     NormalizedPoint m_point;
0625 };
0626 
0627 /**
0628  * This class is an object rect that doesn't own the given pointer, i.e. won't delete it on destruction
0629  * @since 1.7
0630  */
0631 class OKULARCORE_EXPORT NonOwningObjectRect : public ObjectRect
0632 {
0633 public:
0634     NonOwningObjectRect(double left, double top, double right, double bottom, bool ellipse, ObjectType type, void *object);
0635     ~NonOwningObjectRect() override;
0636 };
0637 
0638 /// @cond PRIVATE
0639 /** @internal */
0640 /** @internal */
0641 template<typename T> T *givePtr(T &t)
0642 {
0643     return &t;
0644 }
0645 
0646 /** @internal */
0647 template<typename T> T &deref(T &t)
0648 {
0649     return t;
0650 }
0651 /// @endcond
0652 
0653 /**
0654  * @short An area with normalized coordinates, consisting of NormalizedShape objects.
0655  *
0656  * This is a template class to describe an area which consists of
0657  * multiple shapes of the same type, intersecting or non-intersecting.
0658  * The coordinates are normalized, and can be mapped to a reference area of defined size.
0659  * For more information about the normalized coordinate system, see NormalizedPoint.
0660  *
0661  * Class NormalizedShape \b must have the following functions/operators defined:
0662  * - bool contains( double, double ), whether it contains the given NormalizedPoint
0663  * - bool intersects( NormalizedShape )
0664  * - bool isNull()
0665  * - Shape geometry( int, int ), which maps to the reference area
0666  * - operator|=( NormalizedShape ), which unites two NormalizedShape's
0667  *
0668  * @see RegularAreaRect, NormalizedPoint
0669  */
0670 template<class NormalizedShape, class Shape> class RegularArea : public QList<NormalizedShape>
0671 {
0672 public:
0673     /**
0674      * Returns whether this area contains the normalized point (@p x, @p y).
0675      */
0676     bool contains(double x, double y) const;
0677 
0678     /**
0679      * Returns whether this area contains a NormalizedShape object that equals @p shape.
0680      *
0681      * @note
0682      * The original NormalizedShape objects can be lost if simplify() was called.
0683      */
0684     bool contains(const NormalizedShape &shape) const;
0685 
0686     /**
0687      * Returns whether this area intersects with the given @p area.
0688      */
0689     bool intersects(const RegularArea<NormalizedShape, Shape> *area) const;
0690 
0691     /**
0692      * Returns whether the regular area intersects with the given @p shape.
0693      */
0694     bool intersects(const NormalizedShape &shape) const;
0695 
0696     /**
0697      * Appends the given @p area to this area.
0698      */
0699     void appendArea(const RegularArea<NormalizedShape, Shape> *area);
0700 
0701     /**
0702      * Appends the given @p shape to this area.
0703      */
0704     void appendShape(const NormalizedShape &shape, MergeSide side = MergeAll);
0705 
0706     /**
0707      * Simplifies this regular area by merging its intersecting subareas.
0708      * This might change the effective geometry of this area.
0709      */
0710     void simplify();
0711 
0712     /**
0713      * Returns whether the regular area is a null area.
0714      */
0715     bool isNull() const;
0716 
0717     /**
0718      * Returns the subareas of this regular area
0719      * mapped to a reference area of size @p xScale x @p yScale,
0720      * then translated by @p dx and @p dy.
0721      */
0722     QList<Shape> geometry(int xScale, int yScale, int dx = 0, int dy = 0) const;
0723 
0724     /**
0725      * Transforms the regular area with the operations defined by @p matrix.
0726      */
0727     void transform(const QTransform &matrix);
0728 };
0729 
0730 template<class NormalizedShape, class Shape> void RegularArea<NormalizedShape, Shape>::simplify()
0731 {
0732 #ifdef DEBUG_REGULARAREA
0733     int prev_end = this->count();
0734 #endif
0735     int end = this->count() - 1, x = 0;
0736     for (int i = 0; i < end; ++i) {
0737         if (givePtr((*this)[x])->intersects(deref((*this)[i + 1]))) {
0738             deref((*this)[x]) |= deref((*this)[i + 1]);
0739             this->removeAt(i + 1);
0740             --end;
0741             --i;
0742         } else {
0743             x = i + 1;
0744         }
0745     }
0746 #ifdef DEBUG_REGULARAREA
0747     qCDebug(OkularCoreDebug) << "from" << prev_end << "to" << this->count();
0748 #endif
0749 }
0750 
0751 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::isNull() const
0752 {
0753     if (this->isEmpty()) {
0754         return true;
0755     }
0756 
0757     typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end();
0758     for (; it != itEnd; ++it) {
0759         if (!givePtr(*it)->isNull()) {
0760             return false;
0761         }
0762     }
0763 
0764     return true;
0765 }
0766 
0767 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::intersects(const NormalizedShape &shape) const
0768 {
0769     if (this->isEmpty()) {
0770         return false;
0771     }
0772 
0773     typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end();
0774     for (; it != itEnd; ++it) {
0775         if (!givePtr(*it)->isNull() && givePtr(*it)->intersects(shape)) {
0776             return true;
0777         }
0778     }
0779 
0780     return false;
0781 }
0782 
0783 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::intersects(const RegularArea<NormalizedShape, Shape> *area) const
0784 {
0785     if (this->isEmpty()) {
0786         return false;
0787     }
0788 
0789     typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end();
0790     for (; it != itEnd; ++it) {
0791         typename QList<NormalizedShape>::const_iterator areaIt = area->begin(), areaItEnd = area->end();
0792         for (; areaIt != areaItEnd; ++areaIt) {
0793             if (!(*it).isNull() && (*it).intersects(*areaIt)) {
0794                 return true;
0795             }
0796         }
0797     }
0798 
0799     return false;
0800 }
0801 
0802 template<class NormalizedShape, class Shape> void RegularArea<NormalizedShape, Shape>::appendArea(const RegularArea<NormalizedShape, Shape> *area)
0803 {
0804     typename QList<NormalizedShape>::const_iterator areaIt = area->begin(), areaItEnd = area->end();
0805     for (; areaIt != areaItEnd; ++areaIt) {
0806         this->append(*areaIt);
0807     }
0808 }
0809 
0810 template<class NormalizedShape, class Shape> void RegularArea<NormalizedShape, Shape>::appendShape(const NormalizedShape &shape, MergeSide side)
0811 {
0812     int size = this->count();
0813     // if the list is empty, adds the shape normally
0814     if (size == 0) {
0815         this->append(shape);
0816     } else {
0817         bool intersection = false;
0818         NormalizedShape &last = (*this)[size - 1];
0819 #define O_LAST givePtr(last)
0820 #define O_LAST_R O_LAST->right
0821 #define O_LAST_L O_LAST->left
0822 #define O_LAST_T O_LAST->top
0823 #define O_LAST_B O_LAST->bottom
0824 #define O_NEW givePtr(shape)
0825 #define O_NEW_R O_NEW->right
0826 #define O_NEW_L O_NEW->left
0827 #define O_NEW_T O_NEW->top
0828 #define O_NEW_B O_NEW->bottom
0829         switch (side) {
0830         case MergeRight:
0831             intersection = (O_LAST_R >= O_NEW_L) && (O_LAST_L <= O_NEW_R) && ((O_LAST_T <= O_NEW_T && O_LAST_B >= O_NEW_B) || (O_LAST_T >= O_NEW_T && O_LAST_B <= O_NEW_B));
0832             break;
0833         case MergeBottom:
0834             intersection = (O_LAST_B >= O_NEW_T) && (O_LAST_T <= O_NEW_B) && ((O_LAST_R <= O_NEW_R && O_LAST_L >= O_NEW_L) || (O_LAST_R >= O_NEW_R && O_LAST_L <= O_NEW_L));
0835             break;
0836         case MergeLeft:
0837             intersection = (O_LAST_L <= O_NEW_R) && (O_LAST_R >= O_NEW_L) && ((O_LAST_T <= O_NEW_T && O_LAST_B >= O_NEW_B) || (O_LAST_T >= O_NEW_T && O_LAST_B <= O_NEW_B));
0838             break;
0839         case MergeTop:
0840             intersection = (O_LAST_T <= O_NEW_B) && (O_LAST_B >= O_NEW_T) && ((O_LAST_R <= O_NEW_R && O_LAST_L >= O_NEW_L) || (O_LAST_R >= O_NEW_R && O_LAST_L <= O_NEW_L));
0841             break;
0842         case MergeAll:
0843             intersection = O_LAST->intersects(shape);
0844             break;
0845         }
0846 #undef O_LAST
0847 #undef O_LAST_R
0848 #undef O_LAST_L
0849 #undef O_LAST_T
0850 #undef O_LAST_B
0851 #undef O_NEW
0852 #undef O_NEW_R
0853 #undef O_NEW_L
0854 #undef O_NEW_T
0855 #undef O_NEW_B
0856         // if the new shape intersects with the last shape in the list, then
0857         // merge it with that and delete the shape
0858         if (intersection) {
0859             deref((*this)[size - 1]) |= deref(shape);
0860         } else {
0861             this->append(shape);
0862         }
0863     }
0864 }
0865 
0866 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::contains(double x, double y) const
0867 {
0868     if (this->isEmpty()) {
0869         return false;
0870     }
0871 
0872     typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end();
0873     for (; it != itEnd; ++it) {
0874         if ((*it).contains(x, y)) {
0875             return true;
0876         }
0877     }
0878 
0879     return false;
0880 }
0881 
0882 template<class NormalizedShape, class Shape> bool RegularArea<NormalizedShape, Shape>::contains(const NormalizedShape &shape) const
0883 {
0884     if (this->isEmpty()) {
0885         return false;
0886     }
0887 
0888     return QList<NormalizedShape>::contains(shape);
0889 }
0890 
0891 template<class NormalizedShape, class Shape> QList<Shape> RegularArea<NormalizedShape, Shape>::geometry(int xScale, int yScale, int dx, int dy) const
0892 {
0893     if (this->isEmpty()) {
0894         return QList<Shape>();
0895     }
0896 
0897     QList<Shape> ret;
0898     Shape t;
0899     typename QList<NormalizedShape>::const_iterator it = this->begin(), itEnd = this->end();
0900     for (; it != itEnd; ++it) {
0901         t = givePtr(*it)->geometry(xScale, yScale);
0902         t.translate(dx, dy);
0903         ret.append(t);
0904     }
0905 
0906     return ret;
0907 }
0908 
0909 template<class NormalizedShape, class Shape> void RegularArea<NormalizedShape, Shape>::transform(const QTransform &matrix)
0910 {
0911     if (this->isEmpty()) {
0912         return;
0913     }
0914 
0915     for (int i = 0; i < this->count(); ++i) {
0916         givePtr((*this)[i])->transform(matrix);
0917     }
0918 }
0919 
0920 /**
0921  * This is a list of NormalizedRect, to describe an area consisting of
0922  * multiple rectangles using normalized coordinates.
0923  *
0924  * This area can be mapped to a reference area, resulting in a list of QRects.
0925  * For more information about the normalized coordinate system, see NormalizedPoint.
0926  *
0927  * Okular uses this area e. g. to describe a text highlight area,
0928  * which consists of multiple, intersecting or non-intersecting rectangles.
0929  *
0930  * @see NormalizedRect, NormalizedPoint
0931  */
0932 class OKULARCORE_EXPORT RegularAreaRect : public RegularArea<NormalizedRect, QRect>
0933 {
0934 public:
0935     RegularAreaRect();
0936     RegularAreaRect(const RegularAreaRect &rar);
0937     ~RegularAreaRect();
0938 
0939     RegularAreaRect &operator=(const RegularAreaRect &rar);
0940 
0941 private:
0942     class Private;
0943     Private *const d;
0944 };
0945 
0946 /**
0947  * This class stores the geometry of a highlighting area in normalized coordinates,
0948  * together with highlighting specific information.
0949  */
0950 class HighlightAreaRect : public RegularAreaRect
0951 {
0952 public:
0953     /**
0954      * Creates a new highlight area rect with the coordinates of
0955      * the given @p area.
0956      */
0957     explicit HighlightAreaRect(const RegularAreaRect *area = nullptr);
0958 
0959     /**
0960      * The search ID of the highlight owner.
0961      */
0962     int s_id;
0963 
0964     /**
0965      * The color of the highlight.
0966      */
0967     QColor color;
0968 };
0969 
0970 size_t qHash(const Okular::NormalizedRect &r, size_t seed = 0);
0971 }
0972 
0973 #ifndef QT_NO_DEBUG_STREAM
0974 /**
0975  * Debug operator for normalized @p point.
0976  */
0977 OKULARCORE_EXPORT QDebug operator<<(QDebug str, const Okular::NormalizedPoint &point);
0978 
0979 /**
0980  * Debug operator for normalized @p rect.
0981  */
0982 OKULARCORE_EXPORT QDebug operator<<(QDebug str, const Okular::NormalizedRect &rect);
0983 #endif
0984 
0985 #endif