LCOV - code coverage report
Current view: top level - libreoffice/drawinglayer/source/primitive2d - borderlineprimitive2d.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 148 171 86.5 %
Date: 2012-12-17 Functions: 7 8 87.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             : #include <drawinglayer/geometry/viewinformation2d.hxx>
      21             : #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
      22             : #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
      23             : #include <basegfx/polygon/b2dpolygon.hxx>
      24             : #include <basegfx/polygon/b2dpolygonclipper.hxx>
      25             : #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
      26             : #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
      27             : #include <svtools/borderhelper.hxx>
      28             : #include <numeric>
      29             : #include <algorithm>
      30             : 
      31             : //////////////////////////////////////////////////////////////////////////////
      32             : 
      33             : namespace drawinglayer
      34             : {
      35             :     // fdo#49438: heuristic pseudo hack
      36        5778 :     static bool lcl_UseHairline(double const fW,
      37             :             basegfx::B2DPoint const& rStart, basegfx::B2DPoint const& rEnd,
      38             :             geometry::ViewInformation2D const& rViewInformation)
      39             :     {
      40        5778 :         basegfx::B2DTuple scale;
      41        5778 :         basegfx::B2DTuple translation;
      42             :         double fRotation;
      43             :         double fShear;
      44        5778 :         rViewInformation.getObjectToViewTransformation().decompose(
      45        5778 :                 scale, translation, fRotation, fShear);
      46             :         double const fScale(
      47       11556 :             (rEnd.getX() - rStart.getX() > rEnd.getY() - rStart.getY())
      48       11556 :                 ? scale.getY() : scale.getX());
      49        5778 :         return (fW * fScale < 0.51);
      50             :     }
      51             : 
      52        5232 :     static double lcl_GetCorrectedWidth(double const fW,
      53             :             basegfx::B2DPoint const& rStart, basegfx::B2DPoint const& rEnd,
      54             :             geometry::ViewInformation2D const& rViewInformation)
      55             :     {
      56        5232 :         return (lcl_UseHairline(fW, rStart, rEnd, rViewInformation)) ? 0.0 : fW;
      57             :     }
      58             : 
      59             :     namespace primitive2d
      60             :     {
      61        1554 :         double BorderLinePrimitive2D::getWidth(
      62             :             geometry::ViewInformation2D const& rViewInformation) const
      63             :         {
      64        1554 :             return lcl_GetCorrectedWidth(mfLeftWidth, getStart(), getEnd(),
      65        1554 :                         rViewInformation)
      66        1554 :                  + lcl_GetCorrectedWidth(mfDistance, getStart(), getEnd(),
      67        1554 :                          rViewInformation)
      68        1554 :                  + lcl_GetCorrectedWidth(mfRightWidth, getStart(), getEnd(),
      69        3108 :                          rViewInformation);
      70             :         }
      71             : 
      72         518 :         basegfx::B2DPolyPolygon BorderLinePrimitive2D::getClipPolygon(
      73             :             geometry::ViewInformation2D const& rViewInformation) const
      74             :         {
      75         518 :             basegfx::B2DPolygon clipPolygon;
      76             : 
      77             :             // Get the vectors
      78         518 :             basegfx::B2DVector aVector( getEnd() - getStart() );
      79         518 :             aVector.normalize();
      80         518 :             const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
      81             : 
      82             :             // Get the points
      83         518 :             const double fWidth(getWidth(rViewInformation));
      84             :             const basegfx::B2DVector aLeftOff(
      85         518 :                     aPerpendicular * (-0.5 * std::max(fWidth, 1.0)));
      86             :             const basegfx::B2DVector aRightOff(
      87         518 :                     aPerpendicular * (0.5 * std::max(fWidth, 1.0)));
      88             : 
      89         518 :             const basegfx::B2DVector aSLVector( aLeftOff - ( getExtendLeftStart() * aVector ) );
      90         518 :             clipPolygon.append( basegfx::B2DPoint( getStart() + aSLVector * 2.0 ) );
      91             : 
      92         518 :             clipPolygon.append( getStart( ) );
      93             : 
      94         518 :             const basegfx::B2DVector aSRVector( aRightOff - ( getExtendRightStart() * aVector ) );
      95         518 :             clipPolygon.append( basegfx::B2DPoint( getStart() + aSRVector * 2.0 ) );
      96             : 
      97         518 :             const basegfx::B2DVector aERVector( aRightOff + ( getExtendRightEnd() * aVector ) );
      98         518 :             clipPolygon.append( basegfx::B2DPoint( getEnd() + aERVector * 2.0 ) );
      99             : 
     100         518 :             clipPolygon.append( getEnd( ) );
     101             : 
     102         518 :             const basegfx::B2DVector aELVector( aLeftOff + ( getExtendLeftEnd() * aVector ) );
     103         518 :             clipPolygon.append( basegfx::B2DPoint( getEnd() + aELVector * 2.0 ) );
     104             : 
     105         518 :             clipPolygon.setClosed( true );
     106             : 
     107         518 :             return basegfx::B2DPolyPolygon( clipPolygon );
     108             :         }
     109             : 
     110         522 :         Primitive2DSequence BorderLinePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
     111             :         {
     112         522 :             Primitive2DSequence xRetval;
     113             : 
     114         522 :             if(!getStart().equal(getEnd()) && ( isInsideUsed() || isOutsideUsed() ) )
     115             :             {
     116             :                 // get data and vectors
     117         518 :                 const double fWidth(getWidth(rViewInformation));
     118         518 :                 basegfx::B2DVector aVector(getEnd() - getStart());
     119         518 :                 aVector.normalize();
     120         518 :                 const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
     121             : 
     122             :                 const basegfx::B2DPolyPolygon& aClipRegion =
     123         518 :                     getClipPolygon(rViewInformation);
     124             : 
     125         518 :                 if(isOutsideUsed() && isInsideUsed())
     126             :                 {
     127          28 :                     const double fExt = getWidth(rViewInformation);  // Extend a lot: it'll be clipped after
     128             : 
     129             :                     // both used, double line definition. Create left and right offset
     130          28 :                     xRetval.realloc(2);
     131          28 :                     sal_uInt32 nInsert(0);
     132             : 
     133          28 :                     basegfx::B2DPolygon aGap;
     134             : 
     135             :                     {
     136             :                         // create geometry for left
     137          28 :                         const basegfx::B2DVector aLeftOff(aPerpendicular * (0.5 * (lcl_GetCorrectedWidth(mfLeftWidth, getStart(), getEnd(), rViewInformation) - fWidth + 1)));
     138          28 :                         const basegfx::B2DPoint aTmpStart(getStart() + aLeftOff - ( fExt * aVector));
     139          28 :                         const basegfx::B2DPoint aTmpEnd(getEnd() + aLeftOff + ( fExt * aVector));
     140          28 :                         basegfx::B2DPolygon aLeft;
     141             : 
     142          56 :                         if (lcl_UseHairline(mfLeftWidth, getStart(), getEnd(),
     143          28 :                                     rViewInformation))
     144             :                         {
     145             :                             // create hairline primitive
     146          16 :                             aLeft.append(aTmpStart);
     147          16 :                             aLeft.append(aTmpEnd);
     148             : 
     149             :                             basegfx::B2DPolyPolygon const aClipped =
     150             :                                 basegfx::tools::clipPolygonOnPolyPolygon(
     151          16 :                                     aLeft, aClipRegion, true, true);
     152             : 
     153          16 :                             xRetval[nInsert++] =
     154             :                                 new PolyPolygonHairlinePrimitive2D(
     155             :                                     aClipped,
     156          32 :                                     getRGBColorLeft());
     157             : 
     158          16 :                             aGap.append( getStart() - getExtendLeftStart() * aVector );
     159          16 :                             aGap.append( getEnd() + getExtendLeftEnd() * aVector );
     160             :                         }
     161             :                         else
     162             :                         {
     163             :                             // create filled polygon primitive. Already tried to create thick lines
     164             :                             // with the correct LineWidth, but this leads to problems when no AA
     165             :                             // is available and fat line special case reductions between 0.5 < x < 2.5 line widths
     166             :                             // are executed due to the FilledPolygon-do-not-paint-their-bottom-and-right-lines.
     167          12 :                             const basegfx::B2DVector aLineWidthOffset((lcl_GetCorrectedWidth(mfLeftWidth, getStart(), getEnd(), rViewInformation) * 0.5) * aPerpendicular);
     168             : 
     169          12 :                             aLeft.append(aTmpStart + aLineWidthOffset);
     170          12 :                             aLeft.append(aTmpEnd + aLineWidthOffset);
     171          12 :                             aLeft.append(aTmpEnd - aLineWidthOffset);
     172          12 :                             aLeft.append(aTmpStart - aLineWidthOffset);
     173          12 :                             aLeft.setClosed(true);
     174             : 
     175             :                             basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon(
     176          12 :                                     aLeft, aClipRegion, true, false );
     177             : 
     178          12 :                             aGap.append( aTmpStart + aLineWidthOffset );
     179          12 :                             aGap.append( aTmpEnd + aLineWidthOffset );
     180             : 
     181          12 :                             xRetval[nInsert++] = Primitive2DReference(new PolyPolygonColorPrimitive2D(
     182          24 :                                 aClipped, getRGBColorLeft()));
     183          28 :                         }
     184             :                     }
     185             : 
     186             :                     {
     187             :                         // create geometry for right
     188          28 :                         const basegfx::B2DVector aRightOff(aPerpendicular * (0.5 * (fWidth - lcl_GetCorrectedWidth(mfRightWidth, getStart(), getEnd(), rViewInformation) + 1)));
     189          28 :                         const basegfx::B2DPoint aTmpStart(getStart() + aRightOff - ( fExt * aVector));
     190          28 :                         const basegfx::B2DPoint aTmpEnd(getEnd() + aRightOff + ( fExt * aVector));
     191          28 :                         basegfx::B2DPolygon aRight;
     192             : 
     193          56 :                         if (lcl_UseHairline(mfRightWidth, getStart(), getEnd(),
     194          28 :                                     rViewInformation))
     195             :                         {
     196             :                             // create hairline primitive
     197          16 :                             aRight.append(aTmpStart);
     198          16 :                             aRight.append(aTmpEnd);
     199             : 
     200             :                             basegfx::B2DPolyPolygon const aClipped =
     201             :                                 basegfx::tools::clipPolygonOnPolyPolygon(
     202          16 :                                     aRight, aClipRegion, true, true);
     203             : 
     204          16 :                             xRetval[nInsert++] =
     205             :                                 new PolyPolygonHairlinePrimitive2D(
     206             :                                     aClipped,
     207          32 :                                     getRGBColorRight());
     208             : 
     209          16 :                             aGap.append( getStart() - getExtendRightStart() * aVector );
     210          16 :                             aGap.append( getEnd() + getExtendRightEnd() * aVector );
     211             :                         }
     212             :                         else
     213             :                         {
     214             :                             // create filled polygon primitive
     215          12 :                             const basegfx::B2DVector aLineWidthOffset((lcl_GetCorrectedWidth(mfRightWidth, getStart(), getEnd(), rViewInformation) * 0.5) * aPerpendicular);
     216             : 
     217          12 :                             aRight.append(aTmpStart + aLineWidthOffset);
     218          12 :                             aRight.append(aTmpEnd + aLineWidthOffset);
     219          12 :                             aRight.append(aTmpEnd - aLineWidthOffset);
     220          12 :                             aRight.append(aTmpStart - aLineWidthOffset);
     221          12 :                             aRight.setClosed(true);
     222             : 
     223             :                             basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon(
     224          12 :                                     aRight, aClipRegion, true, false );
     225             : 
     226          12 :                             xRetval[nInsert++] = Primitive2DReference(new PolyPolygonColorPrimitive2D(
     227          24 :                                 aClipped, getRGBColorRight()));
     228             : 
     229          12 :                             aGap.append( aTmpEnd - aLineWidthOffset );
     230          12 :                             aGap.append( aTmpStart - aLineWidthOffset );
     231          28 :                         }
     232             :                     }
     233             : 
     234          28 :                     if (hasGapColor() && aGap.count() == 4)
     235             :                     {
     236           0 :                         xRetval.realloc( xRetval.getLength() + 1 );
     237             :                         // create geometry for filled gap
     238           0 :                         aGap.setClosed( true );
     239             : 
     240             :                         basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon(
     241           0 :                                 aGap, aClipRegion, true, false );
     242             : 
     243           0 :                         xRetval[nInsert++] = Primitive2DReference( new PolyPolygonColorPrimitive2D(
     244           0 :                               aClipped, getRGBColorGap() ) );
     245          28 :                     }
     246             :                 }
     247             :                 else
     248             :                 {
     249             :                     // single line, create geometry
     250         490 :                     basegfx::B2DPolygon aPolygon;
     251         490 :                     const double fExt = getWidth(rViewInformation);  // Extend a lot: it'll be clipped after
     252         490 :                     const basegfx::B2DPoint aTmpStart(getStart() - (fExt * aVector));
     253         490 :                     const basegfx::B2DPoint aTmpEnd(getEnd() + (fExt * aVector));
     254         490 :                     xRetval.realloc(1);
     255             : 
     256             :                     // Get which is the line to show
     257         490 :                     bool bIsSolidline = isSolidLine();
     258         490 :                     double nWidth = getLeftWidth();
     259         490 :                     basegfx::BColor aColor = getRGBColorLeft();
     260         490 :                     if ( basegfx::fTools::equal( 0.0, mfLeftWidth ) )
     261             :                     {
     262          42 :                         nWidth = getRightWidth();
     263          42 :                         aColor = getRGBColorRight();
     264             :                     }
     265             :                     bool const bIsHairline = lcl_UseHairline(
     266         490 :                             nWidth, getStart(), getEnd(), rViewInformation);
     267             :                     nWidth = lcl_GetCorrectedWidth(nWidth,
     268         490 :                                 getStart(), getEnd(), rViewInformation);
     269             : 
     270         490 :                     if(bIsHairline && bIsSolidline)
     271             :                     {
     272             :                         // create hairline primitive
     273         356 :                         aPolygon.append( getStart() );
     274         356 :                         aPolygon.append( getEnd() );
     275             : 
     276         356 :                         xRetval[0] = Primitive2DReference(new PolygonHairlinePrimitive2D(
     277             :                             aPolygon,
     278         712 :                             aColor));
     279             :                     }
     280             :                     else
     281             :                     {
     282             :                         // create filled polygon primitive
     283         134 :                         const basegfx::B2DVector aLineWidthOffset(((nWidth + 1) * 0.5) * aPerpendicular);
     284         134 :                         basegfx::B2DVector aScale( rViewInformation.getInverseObjectToViewTransformation() * aVector );
     285             : 
     286         134 :                         aPolygon.append( aTmpStart );
     287         134 :                         aPolygon.append( aTmpEnd );
     288             : 
     289             :                         basegfx::B2DPolyPolygon aDashed = svtools::ApplyLineDashing(
     290         134 :                                aPolygon, getStyle(), MAP_PIXEL, aScale.getLength() );
     291         268 :                         for (sal_uInt32 i = 0; i < aDashed.count(); i++ )
     292             :                         {
     293         134 :                             basegfx::B2DPolygon aDash = aDashed.getB2DPolygon( i );
     294         134 :                             basegfx::B2DPoint aDashStart = aDash.getB2DPoint( 0 );
     295         134 :                             basegfx::B2DPoint aDashEnd = aDash.getB2DPoint( aDash.count() - 1 );
     296             : 
     297         134 :                             basegfx::B2DPolygon aDashPolygon;
     298         134 :                             aDashPolygon.append( aDashStart + aLineWidthOffset );
     299         134 :                             aDashPolygon.append( aDashEnd + aLineWidthOffset );
     300         134 :                             aDashPolygon.append( aDashEnd - aLineWidthOffset );
     301         134 :                             aDashPolygon.append( aDashStart - aLineWidthOffset );
     302         134 :                             aDashPolygon.setClosed( true );
     303             : 
     304             :                             basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon(
     305         134 :                                 aDashPolygon, aClipRegion, true, false );
     306             : 
     307         134 :                             if ( aClipped.count() )
     308         134 :                                 aDashed.setB2DPolygon( i, aClipped.getB2DPolygon( 0 ) );
     309         134 :                         }
     310             : 
     311         134 :                         xRetval[0] = Primitive2DReference(new PolyPolygonColorPrimitive2D(
     312         268 :                                 basegfx::B2DPolyPolygon( aDashed ), aColor));
     313         490 :                     }
     314         518 :                 }
     315             :             }
     316             : 
     317         522 :             return xRetval;
     318             :         }
     319             : 
     320         522 :         BorderLinePrimitive2D::BorderLinePrimitive2D(
     321             :             const basegfx::B2DPoint& rStart,
     322             :             const basegfx::B2DPoint& rEnd,
     323             :             double fLeftWidth,
     324             :             double fDistance,
     325             :             double fRightWidth,
     326             :             double fExtendLeftStart,
     327             :             double fExtendLeftEnd,
     328             :             double fExtendRightStart,
     329             :             double fExtendRightEnd,
     330             :             const basegfx::BColor& rRGBColorRight,
     331             :             const basegfx::BColor& rRGBColorLeft,
     332             :             const basegfx::BColor& rRGBColorGap,
     333             :             bool bHasGapColor,
     334             :             const short nStyle)
     335             :         :   BufferedDecompositionPrimitive2D(),
     336             :             maStart(rStart),
     337             :             maEnd(rEnd),
     338             :             mfLeftWidth(fLeftWidth),
     339             :             mfDistance(fDistance),
     340             :             mfRightWidth(fRightWidth),
     341             :             mfExtendLeftStart(fExtendLeftStart),
     342             :             mfExtendLeftEnd(fExtendLeftEnd),
     343             :             mfExtendRightStart(fExtendRightStart),
     344             :             mfExtendRightEnd(fExtendRightEnd),
     345             :             maRGBColorRight(rRGBColorRight),
     346             :             maRGBColorLeft(rRGBColorLeft),
     347             :             maRGBColorGap(rRGBColorGap),
     348             :             mbHasGapColor(bHasGapColor),
     349         522 :             mnStyle(nStyle)
     350             :         {
     351         522 :         }
     352             : 
     353           0 :         bool BorderLinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
     354             :         {
     355           0 :             if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
     356             :             {
     357           0 :                 const BorderLinePrimitive2D& rCompare = (BorderLinePrimitive2D&)rPrimitive;
     358             : 
     359           0 :                 return (getStart() == rCompare.getStart()
     360           0 :                     && getEnd() == rCompare.getEnd()
     361           0 :                     && getLeftWidth() == rCompare.getLeftWidth()
     362           0 :                     && getDistance() == rCompare.getDistance()
     363           0 :                     && getRightWidth() == rCompare.getRightWidth()
     364           0 :                     && getExtendLeftStart() == rCompare.getExtendLeftStart()
     365           0 :                     && getExtendLeftEnd() == rCompare.getExtendLeftEnd()
     366           0 :                     && getExtendRightStart() == rCompare.getExtendRightStart()
     367           0 :                     && getExtendRightEnd() == rCompare.getExtendRightEnd()
     368           0 :                     && getRGBColorRight() == rCompare.getRGBColorRight()
     369           0 :                     && getRGBColorLeft() == rCompare.getRGBColorLeft()
     370           0 :                     && getRGBColorGap() == rCompare.getRGBColorGap()
     371           0 :                     && hasGapColor() == rCompare.hasGapColor()
     372           0 :                     && getStyle() == rCompare.getStyle());
     373             :             }
     374             : 
     375           0 :             return false;
     376             :         }
     377             : 
     378             :         // provide unique ID
     379         522 :         ImplPrimitrive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D)
     380             : 
     381             :     } // end of namespace primitive2d
     382             : } // end of namespace drawinglayer
     383             : 
     384             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10