LCOV - code coverage report
Current view: top level - libreoffice/filter/source/graphicfilter/ipict - shape.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 51 138 37.0 %
Date: 2012-12-27 Functions: 3 8 37.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : /** Osnola:
      21             : IMPORTANT NOTE: some Quickdraw lines/frames can not be "quickly" drawn exactly:
      22             : for instance, when PenSize=(1,1), the line from (0,0) to (8,0)
      23             : corresponds to the rectangle (0,0)(0,1)(9,1)(9,0), which can only be drawn
      24             :  by drawing a rectangle. Drawing a non horizontal/vertical will imply to draw
      25             : a polygon, ...
      26             : Similarly, drawing the frame of a rectangle (0,0)(0,1)(9,1)(9,0) when PenSize=(1,1),
      27             : will imply to draw a rectangle (0.5,0.5)(0.5,8.5)(8.5,8.5)(8.5,0.5) with linewidth=1...
      28             : 
      29             : Here, we choose:
      30             : - for horizontal/vertical lines and line with length less than five to draw the real line,
      31             : - in the other case, we keep the same shape (even if this means some "bad" coordinates)
      32             : */
      33             : 
      34             : #include <basegfx/polygon/b2dpolygon.hxx>
      35             : #include <basegfx/polygon/b2dpolygontools.hxx>
      36             : #include "shape.hxx"
      37             : 
      38             : namespace PictReaderShapePrivate {
      39             :   /** returns an inside rectangle knowing the penSize in order to obtain the ``correct'' position
      40             :       when we draw a frame in wide length*/
      41           0 :   Rectangle contractRectangle(bool drawFrame, Rectangle const &rect, Size const &pSize) {
      42           0 :     if (!drawFrame) return rect;
      43           0 :     long penSize=(pSize.Width()+pSize.Height())/2;
      44           0 :     if (2*penSize > rect.Right()-rect.Left()) penSize = (rect.Right()-rect.Left()+1)/2;
      45           0 :     if (2*penSize > rect.Bottom()-rect.Top()) penSize = (rect.Bottom()-rect.Top()+1)/2;
      46           0 :     long const X[2] = { rect.Left()+penSize/2, rect.Right()-(penSize+1)/2 };
      47           0 :     long const Y[2] = { rect.Top()+penSize/2, rect.Bottom()-(penSize+1)/2 };
      48           0 :     return Rectangle(Point(X[0],Y[0]), Point(X[1], Y[1]));
      49             :   }
      50             : }
      51             : 
      52             : namespace PictReaderShape {
      53             :   //--------- draws a horizontal/vertical/small line (by creating a "rectangle/polygon")  ---------
      54          53 :   bool drawLineHQ(VirtualDevice *dev, Point const &orig, Point const &dest, Size const &pSize) {
      55          53 :     long dir[2] = { dest.X()-orig.X(), dest.Y()-orig.Y() };
      56          53 :     bool vertic = dir[0] == 0;
      57          53 :     bool horiz = dir[1] == 0;
      58          53 :     if (!horiz && !vertic && dir[0]*dir[0]+dir[1]*dir[1] > 25) return false;
      59             : 
      60          33 :     long X[2]={ orig.X(), dest.X() }, Y[2] = { orig.Y(), dest.Y() };
      61             :     using namespace basegfx;
      62          33 :     B2DPolygon poly;
      63          33 :     if (horiz || vertic) {
      64          33 :       if (horiz) {
      65          23 :     if (X[0] < X[1]) X[1]+=pSize.Width();
      66          12 :     else X[0]+=pSize.Width();
      67          23 :     Y[1] += pSize.Height();
      68             :       }
      69             :       else  {
      70          10 :     if (Y[0] < Y[1]) Y[1]+=pSize.Height();
      71           5 :     else Y[0]+=pSize.Height();
      72          10 :     X[1] += pSize.Width();
      73             :       }
      74          33 :       poly.append(B2DPoint(X[0], Y[0])); poly.append(B2DPoint(X[1], Y[0]));
      75          33 :       poly.append(B2DPoint(X[1], Y[1])); poly.append(B2DPoint(X[0], Y[1]));
      76          33 :       poly.append(B2DPoint(X[0], Y[0]));
      77             :     }
      78             :     else {
      79           0 :       long origPt[4][2] = { { orig.X(), orig.Y() }, { orig.X()+pSize.Width(), orig.Y() },
      80           0 :                { orig.X()+pSize.Width(), orig.Y()+pSize.Height() },
      81           0 :                { orig.X(), orig.Y()+pSize.Height() }};
      82           0 :       long origAvoid = dir[0] > 0 ? (dir[1] > 0 ? 2 : 1) : (dir[1] > 0 ? 3 : 0);
      83           0 :       long destPt[4][2] = { { dest.X(), dest.Y() }, { dest.X()+pSize.Width(), dest.Y() },
      84           0 :                { dest.X()+pSize.Width(), dest.Y()+pSize.Height() },
      85           0 :                { dest.X(), dest.Y()+pSize.Height() }};
      86           0 :       for (int w = origAvoid+1; w < origAvoid+4; w++) {
      87           0 :     int wh = (w%4);
      88           0 :     poly.append(B2DPoint(origPt[wh][0], origPt[wh][1]));
      89             :       }
      90           0 :       for (int w = origAvoid+3; w < origAvoid+6; w++) {
      91           0 :     int wh = (w%4);
      92           0 :     poly.append(B2DPoint(destPt[wh][0], destPt[wh][1]));
      93             :       }
      94           0 :       int wh = (origAvoid+1)%4;
      95           0 :       poly.append(B2DPoint(origPt[wh][0], origPt[wh][1]));
      96             :     }
      97             : 
      98             :     // HACK: here we use the line coloring when drawing the shape
      99             :     //       must be changed if other parameter are changed to draw
     100             :     //       a line/fill shape
     101          33 :     Color oldFColor = dev->GetFillColor(), oldLColor = dev->GetLineColor();
     102          33 :     dev->SetFillColor(oldLColor); dev->SetLineColor(Color(COL_TRANSPARENT));
     103          33 :     dev->DrawPolygon(poly);
     104          33 :     dev->SetLineColor(oldLColor); dev->SetFillColor(oldFColor);
     105          33 :     return true;
     106             :   }
     107             : 
     108             :   //
     109             :   //-------------------- draws a line --------------------
     110             :   //
     111          53 :   void drawLine(VirtualDevice *dev, Point const &orig, Point const &dest, Size const &pSize) {
     112         106 :     if (drawLineHQ(dev,orig,dest,pSize)) return;
     113             : 
     114          20 :     long penSize=(pSize.Width()+pSize.Height())/2;
     115          20 :     long decal[2] = { pSize.Width()/2, pSize.Height()/2};
     116             : 
     117             :     using namespace basegfx;
     118          20 :     B2DPolygon poly;
     119          20 :     poly.append(B2DPoint(double(orig.X()+decal[0]), double(orig.Y()+decal[1])));
     120          20 :     poly.append(B2DPoint(double(dest.X()+decal[0]), double(dest.Y()+decal[1])));
     121          20 :     dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLINEJOIN_NONE);
     122             :   }
     123             : 
     124             :   //--------------------  draws a rectangle --------------------
     125             :   /* Note(checkme): contradically with the QuickDraw's reference 3-23, it seems better to consider
     126             :      that the frame/content of a rectangle appears inside the given rectangle. Does a conversion
     127             :      appear between the pascal functions and the data stored in the file ? */
     128           0 :   void drawRectangle(VirtualDevice *dev, bool drawFrame, Rectangle const &orig, Size const &pSize) {
     129           0 :     int penSize=(pSize.Width()+pSize.Height())/2;
     130           0 :     Rectangle rect = PictReaderShapePrivate::contractRectangle(drawFrame, orig, pSize);
     131           0 :     long const X[2] = { rect.Left(), rect.Right() };
     132           0 :     long const Y[2] = { rect.Top(), rect.Bottom() };
     133             : 
     134             :     using namespace basegfx;
     135           0 :     B2DPolygon poly;
     136           0 :     poly.append(B2DPoint(X[0], Y[0])); poly.append(B2DPoint(X[1], Y[0]));
     137           0 :     poly.append(B2DPoint(X[1], Y[1])); poly.append(B2DPoint(X[0], Y[1]));
     138           0 :     poly.append(B2DPoint(X[0], Y[0]));
     139             : 
     140           0 :     if (drawFrame)
     141           0 :       dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLINEJOIN_NONE);
     142             :     else
     143           0 :       dev->DrawPolygon(poly);
     144           0 :   }
     145             : 
     146             :   //--------------------  draws an ellipse --------------------
     147           0 :   void drawEllipse(VirtualDevice *dev, bool drawFrame, Rectangle const &orig, Size const &pSize) {
     148           0 :     int penSize=(pSize.Width()+pSize.Height())/2;
     149           0 :     Rectangle oval = PictReaderShapePrivate::contractRectangle(drawFrame, orig, pSize);
     150             :     using namespace basegfx;
     151           0 :     long const X[2] = { oval.Left(), oval.Right() };
     152           0 :     long const Y[2] = { oval.Top(), oval.Bottom() };
     153           0 :     B2DPoint center(0.5*(X[1]+X[0]), 0.5*(Y[1]+Y[0]));
     154           0 :     B2DPolygon poly = tools::createPolygonFromEllipse(center, 0.5*(X[1]-X[0]), 0.5*(Y[1]-Y[0]));
     155           0 :     if (drawFrame)
     156           0 :       dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLINEJOIN_NONE);
     157             :     else
     158           0 :       dev->DrawPolygon(poly);
     159           0 :   }
     160             : 
     161             :   //--------------------  draws an arc/pie --------------------
     162           0 :   void drawArc(VirtualDevice *dev, bool drawFrame, Rectangle const &orig, const double& angle1, const double& angle2, Size const &pSize) {
     163           0 :     int penSize=(pSize.Width()+pSize.Height())/2;
     164           0 :     Rectangle arc = PictReaderShapePrivate::contractRectangle(drawFrame, orig, pSize);
     165             :     using namespace basegfx;
     166             : 
     167           0 :     double const PI2 = M_PI/2.0;
     168             :     // pict angle are CW with 0 at twelve oclock ( with Y-axis inverted)...
     169           0 :     double angl1 = angle1-PI2;
     170           0 :     double angl2 = angle2-PI2;
     171           0 :     long const X[2] = { arc.Left(), arc.Right() };
     172           0 :     long const Y[2] = { arc.Top(), arc.Bottom() };
     173           0 :     B2DPoint center(0.5*(X[1]+X[0]), 0.5*(Y[1]+Y[0]));
     174             : 
     175             :     // We must have angl1 between 0 and F_2PI
     176           0 :     while (angl1 < 0.0) { angl1 += F_2PI; angl2 += F_2PI; }
     177           0 :     while (angl1 >= F_2PI) { angl1  -= F_2PI; angl2 -= F_2PI; }
     178             : 
     179             :     // if this happen, we want a complete circle
     180             :     // so we set angl2 slightly less than angl1
     181           0 :     if (angl2 >= angl1+F_2PI) angl2 = angl1-0.001;
     182             : 
     183             :     // We must have angl2 between 0 and F_2PI
     184           0 :     while (angl2 < 0.0) angl2 += F_2PI;
     185           0 :     while (angl2 >= F_2PI) angl2 -= F_2PI;
     186             : 
     187           0 :     B2DPolygon poly = tools::createPolygonFromEllipseSegment(center, 0.5*(X[1]-X[0]), 0.5*(Y[1]-Y[0]), angl1, angl2);
     188           0 :     if (drawFrame)
     189           0 :       dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLINEJOIN_NONE);
     190             :     else {
     191             :       // adds circle's center
     192           0 :       poly.append(center);
     193           0 :       dev->DrawPolygon(poly);
     194           0 :     }
     195           0 :   }
     196             :   //--------------------  draws a rectangle with round corner --------------------
     197           0 :   void drawRoundRectangle(VirtualDevice *dev, bool drawFrame, Rectangle const &orig, Size const &ovalSize, Size const &pSize) {
     198           0 :     int penSize=(pSize.Width()+pSize.Height())/2;
     199           0 :     Rectangle oval = PictReaderShapePrivate::contractRectangle(drawFrame, orig, pSize);
     200           0 :     int ovalW=ovalSize.Width(), ovalH=ovalSize.Height();
     201             :     using namespace basegfx;
     202           0 :     long const X[2] = { oval.Left(), oval.Right() };
     203           0 :     long const Y[2] = { oval.Top(), oval.Bottom() };
     204           0 :     long width = X[1] - X[0];
     205           0 :     long height = Y[1] - Y[0];
     206           0 :     if (ovalW > width) ovalW = static_cast< int >( width );
     207           0 :     if (ovalH > height) ovalH = static_cast< int >( height );
     208             : 
     209           0 :     B2DRectangle rect(B2DPoint(X[0],Y[0]), B2DPoint(X[1],Y[1]));
     210           0 :     B2DPolygon poly = tools::createPolygonFromRect(rect, (width != 0.0) ? ovalW/width : 0.0, (height != 0.0) ? ovalH/height : 0.0);
     211             : 
     212           0 :     if (drawFrame)
     213           0 :       dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLINEJOIN_NONE);
     214             :     else
     215           0 :       dev->DrawPolygon(poly);
     216           0 :   }
     217             : 
     218             :   //--------------------  draws a polygon --------------------
     219          29 :   void drawPolygon(VirtualDevice *dev, bool drawFrame, Polygon const &orig, Size const &pSize) {
     220          29 :     int penSize=(pSize.Width()+pSize.Height())/2;
     221          29 :     long decalTL[2] = {0, 0}, decalBR[2] = { pSize.Width(), pSize.Height()};
     222          29 :     if (drawFrame) {
     223           0 :       decalTL[0] += penSize/2; decalTL[1] += penSize/2;
     224           0 :       decalBR[0] -= (penSize+1)/2; decalBR[1] -= (penSize+1)/2;
     225             :     }
     226             :     // Quickdraw Drawing Reference 3-82: the pen size is only used for frame
     227          29 :     else decalBR[0] = decalBR[1] = 0;
     228             : 
     229             : 
     230          29 :     int numPt = orig.GetSize();
     231          58 :     if (numPt <= 1) return;
     232             : 
     233             :     // we compute a barycenter of the point to define the extended direction of each point
     234          29 :     double bary[2] = { 0.0, 0.0 };
     235        1330 :     for (int i = 0; i < numPt; i++) {
     236        1301 :       Point const &pt = orig.GetPoint(i);
     237        1301 :       bary[0] += double(pt.X()); bary[1] += double(pt.Y());
     238             :     }
     239          29 :     bary[0]/=double(numPt); bary[1]/=double(numPt);
     240             : 
     241             :     using namespace basegfx;
     242          29 :     B2DPolygon poly;
     243             :     // Note: a polygon can be open, so we must not close it when we draw the frame
     244        1330 :     for (int i = 0; i < numPt; i++) {
     245        1301 :       Point const &pt = orig.GetPoint(i);
     246        1301 :       double x = (double(pt.X()) < bary[0]) ? pt.X()+decalTL[0] : pt.X()+decalBR[0];
     247        1301 :       double y = (double(pt.Y()) < bary[1]) ? pt.Y()+decalTL[1] : pt.Y()+decalBR[1];
     248        1301 :       poly.append(B2DPoint(x, y));
     249             :     }
     250          29 :     if (drawFrame)
     251           0 :       dev->DrawPolyLine(poly, double(penSize), basegfx::B2DLINEJOIN_NONE);
     252             :     else
     253          29 :       dev->DrawPolygon(poly);
     254             :   }
     255             : 
     256             : 
     257             : }
     258             : 
     259             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10