LCOV - code coverage report
Current view: top level - drawinglayer/source/primitive2d - borderlineprimitive2d.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 144 171 84.2 %
Date: 2015-06-13 12:38:46 Functions: 10 11 90.9 %
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             : namespace drawinglayer {
      32             : 
      33             : namespace {
      34             : 
      35         144 : void moveLine(basegfx::B2DPolygon& rPoly, double fGap, const basegfx::B2DVector& rVector)
      36             : {
      37         144 :     if (basegfx::fTools::equalZero(rVector.getX()))
      38             :     {
      39          70 :         basegfx::B2DHomMatrix aMat(1, 0, fGap, 0, 1, 0);
      40          70 :         rPoly.transform(aMat);
      41             :     }
      42          74 :     else if (basegfx::fTools::equalZero(rVector.getY()))
      43             :     {
      44          74 :         basegfx::B2DHomMatrix aMat(1, 0, 0, 0, 1, fGap);
      45          74 :         rPoly.transform(aMat);
      46             :     }
      47         144 : }
      48             : 
      49          19 : primitive2d::Primitive2DReference makeHairLinePrimitive(
      50             :     const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd, const basegfx::B2DVector& rVector,
      51             :     const basegfx::BColor& rColor, double fGap)
      52             : {
      53          19 :     basegfx::B2DPolygon aPolygon;
      54          19 :     aPolygon.append(rStart);
      55          19 :     aPolygon.append(rEnd);
      56          19 :     moveLine(aPolygon, fGap, rVector);
      57             : 
      58          19 :     return primitive2d::Primitive2DReference(new primitive2d::PolygonHairlinePrimitive2D(aPolygon, rColor));
      59             : }
      60             : 
      61         125 : primitive2d::Primitive2DReference makeSolidLinePrimitive(
      62             :     const basegfx::B2DPolyPolygon& rClipRegion, const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd,
      63             :     const basegfx::B2DVector& rVector, const basegfx::BColor& rColor, double fLineWidth, double fGap)
      64             : {
      65         125 :     const basegfx::B2DVector aPerpendicular = basegfx::getPerpendicular(rVector);
      66         250 :     const basegfx::B2DVector aLineWidthOffset = ((fLineWidth + 1.0) * 0.5) * aPerpendicular;
      67             : 
      68         250 :     basegfx::B2DPolygon aPolygon;
      69         125 :     aPolygon.append(rStart + aLineWidthOffset);
      70         125 :     aPolygon.append(rEnd + aLineWidthOffset);
      71         125 :     aPolygon.append(rEnd - aLineWidthOffset);
      72         125 :     aPolygon.append(rStart - aLineWidthOffset);
      73         125 :     aPolygon.setClosed(true);
      74             : 
      75         125 :     moveLine(aPolygon, fGap, rVector);
      76             : 
      77             :     basegfx::B2DPolyPolygon aClipped =
      78         250 :         basegfx::tools::clipPolygonOnPolyPolygon(aPolygon, rClipRegion, true, false);
      79             : 
      80         125 :     if (aClipped.count())
      81         125 :         aPolygon = aClipped.getB2DPolygon(0);
      82             : 
      83             :     return primitive2d::Primitive2DReference(
      84         250 :         new primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aPolygon), rColor));
      85             : }
      86             : 
      87             : }
      88             : 
      89             :     // fdo#49438: heuristic pseudo hack
      90        1392 :     static bool lcl_UseHairline(double const fW,
      91             :             basegfx::B2DPoint const& rStart, basegfx::B2DPoint const& rEnd,
      92             :             geometry::ViewInformation2D const& rViewInformation)
      93             :     {
      94        1392 :         basegfx::B2DTuple scale;
      95        2784 :         basegfx::B2DTuple translation;
      96             :         double fRotation;
      97             :         double fShear;
      98        1392 :         rViewInformation.getObjectToViewTransformation().decompose(
      99        1392 :                 scale, translation, fRotation, fShear);
     100             :         double const fScale(
     101        1392 :             (rEnd.getX() - rStart.getX() > rEnd.getY() - rStart.getY())
     102        1392 :                 ? scale.getY() : scale.getX());
     103        2784 :         return (fW * fScale < 0.51);
     104             :     }
     105             : 
     106        1146 :     static double lcl_GetCorrectedWidth(double const fW,
     107             :             basegfx::B2DPoint const& rStart, basegfx::B2DPoint const& rEnd,
     108             :             geometry::ViewInformation2D const& rViewInformation)
     109             :     {
     110        1146 :         return (lcl_UseHairline(fW, rStart, rEnd, rViewInformation)) ? 0.0 : fW;
     111             :     }
     112             : 
     113             :     namespace primitive2d
     114             :     {
     115         348 :         double BorderLinePrimitive2D::getWidth(
     116             :             geometry::ViewInformation2D const& rViewInformation) const
     117             :         {
     118         348 :             return lcl_GetCorrectedWidth(mfLeftWidth, getStart(), getEnd(),
     119         348 :                         rViewInformation)
     120         696 :                  + lcl_GetCorrectedWidth(mfDistance, getStart(), getEnd(),
     121         348 :                          rViewInformation)
     122         348 :                  + lcl_GetCorrectedWidth(mfRightWidth, getStart(), getEnd(),
     123         348 :                          rViewInformation);
     124             :         }
     125             : 
     126         174 :         basegfx::B2DPolyPolygon BorderLinePrimitive2D::getClipPolygon(
     127             :             geometry::ViewInformation2D const& rViewInformation) const
     128             :         {
     129         174 :             basegfx::B2DPolygon clipPolygon;
     130             : 
     131             :             // Get the vectors
     132         348 :             basegfx::B2DVector aVector( getEnd() - getStart() );
     133         174 :             aVector.normalize();
     134         348 :             const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
     135             : 
     136             :             // Get the points
     137         174 :             const double fWidth(getWidth(rViewInformation));
     138             :             const basegfx::B2DVector aLeftOff(
     139         348 :                     aPerpendicular * (-0.5 * std::max(fWidth, 1.0)));
     140             :             const basegfx::B2DVector aRightOff(
     141         348 :                     aPerpendicular * (0.5 * std::max(fWidth, 1.0)));
     142             : 
     143         348 :             const basegfx::B2DVector aSLVector( aLeftOff - ( getExtendLeftStart() * aVector ) );
     144         174 :             clipPolygon.append( basegfx::B2DPoint( getStart() + aSLVector * 2.0 ) );
     145             : 
     146         174 :             clipPolygon.append( getStart( ) );
     147             : 
     148         348 :             const basegfx::B2DVector aSRVector( aRightOff - ( getExtendRightStart() * aVector ) );
     149         174 :             clipPolygon.append( basegfx::B2DPoint( getStart() + aSRVector * 2.0 ) );
     150             : 
     151         348 :             const basegfx::B2DVector aERVector( aRightOff + ( getExtendRightEnd() * aVector ) );
     152         174 :             clipPolygon.append( basegfx::B2DPoint( getEnd() + aERVector * 2.0 ) );
     153             : 
     154         174 :             clipPolygon.append( getEnd( ) );
     155             : 
     156         348 :             const basegfx::B2DVector aELVector( aLeftOff + ( getExtendLeftEnd() * aVector ) );
     157         174 :             clipPolygon.append( basegfx::B2DPoint( getEnd() + aELVector * 2.0 ) );
     158             : 
     159         174 :             clipPolygon.setClosed( true );
     160             : 
     161         348 :             return basegfx::B2DPolyPolygon( clipPolygon );
     162             :         }
     163             : 
     164         174 :         Primitive2DSequence BorderLinePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
     165             :         {
     166         174 :             Primitive2DSequence xRetval;
     167             : 
     168         174 :             if(!getStart().equal(getEnd()) && ( isInsideUsed() || isOutsideUsed() ) )
     169             :             {
     170             :                 // get data and vectors
     171         174 :                 basegfx::B2DVector aVector(getEnd() - getStart());
     172         174 :                 aVector.normalize();
     173         348 :                 const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
     174             : 
     175             :                 const basegfx::B2DPolyPolygon& aClipRegion =
     176         348 :                     getClipPolygon(rViewInformation);
     177             : 
     178         174 :                 if(isOutsideUsed() && isInsideUsed())
     179             :                 {
     180          72 :                     const double fExt = getWidth(rViewInformation);  // Extend a lot: it'll be clipped later.
     181          72 :                     const basegfx::B2DPoint aTmpStart(getStart() - (fExt * aVector));
     182         144 :                     const basegfx::B2DPoint aTmpEnd(getEnd() + (fExt * aVector));
     183             : 
     184          72 :                     xRetval.realloc(2);
     185             : 
     186          72 :                     double fLeftWidth = getLeftWidth();
     187          72 :                     bool bLeftHairline = lcl_UseHairline(fLeftWidth, getStart(), getEnd(), rViewInformation);
     188          72 :                     if (bLeftHairline)
     189           4 :                         fLeftWidth = 0.0;
     190             : 
     191          72 :                     double fRightWidth = getRightWidth();
     192          72 :                     bool bRightHairline = lcl_UseHairline(fRightWidth, getStart(), getEnd(), rViewInformation);
     193          72 :                     if (bRightHairline)
     194          15 :                         fRightWidth = 0.0;
     195             : 
     196             :                     // "inside" line
     197             : 
     198          72 :                     if (bLeftHairline)
     199           8 :                         xRetval[0] = makeHairLinePrimitive(
     200           8 :                             getStart(), getEnd(), aVector, getRGBColorLeft(), 0.0);
     201             :                     else
     202         204 :                         xRetval[0] = makeSolidLinePrimitive(
     203         136 :                             aClipRegion, aTmpStart, aTmpEnd, aVector, getRGBColorLeft(), fLeftWidth, -fLeftWidth/2.0);
     204             : 
     205             :                     // "outside" line
     206             : 
     207          72 :                     if (bRightHairline)
     208          45 :                         xRetval[1] = makeHairLinePrimitive(
     209          30 :                             getStart(), getEnd(), aVector, getRGBColorRight(), fLeftWidth+mfDistance);
     210             :                     else
     211         228 :                         xRetval[1] = makeSolidLinePrimitive(
     212         243 :                             aClipRegion, aTmpStart, aTmpEnd, aVector, getRGBColorRight(), fRightWidth, mfDistance+fRightWidth/2.0);
     213             :                 }
     214             :                 else
     215             :                 {
     216             :                     // single line, create geometry
     217         102 :                     basegfx::B2DPolygon aPolygon;
     218         102 :                     const double fExt = getWidth(rViewInformation);  // Extend a lot: it'll be clipped after
     219         204 :                     const basegfx::B2DPoint aTmpStart(getStart() - (fExt * aVector));
     220         204 :                     const basegfx::B2DPoint aTmpEnd(getEnd() + (fExt * aVector));
     221             : 
     222             :                     // Get which is the line to show
     223         102 :                     bool bIsSolidline = isSolidLine();
     224         102 :                     double nWidth = getLeftWidth();
     225         204 :                     basegfx::BColor aColor = getRGBColorLeft();
     226         102 :                     if ( basegfx::fTools::equal( 0.0, mfLeftWidth ) )
     227             :                     {
     228           0 :                         nWidth = getRightWidth();
     229           0 :                         aColor = getRGBColorRight();
     230             :                     }
     231             :                     bool const bIsHairline = lcl_UseHairline(
     232         102 :                             nWidth, getStart(), getEnd(), rViewInformation);
     233             :                     nWidth = lcl_GetCorrectedWidth(nWidth,
     234         102 :                                 getStart(), getEnd(), rViewInformation);
     235             : 
     236         102 :                     if(bIsHairline && bIsSolidline)
     237             :                     {
     238             :                         // create hairline primitive
     239          69 :                         aPolygon.append( getStart() );
     240          69 :                         aPolygon.append( getEnd() );
     241             : 
     242          69 :                         xRetval.realloc(1);
     243         138 :                         xRetval[0] = Primitive2DReference(new PolygonHairlinePrimitive2D(
     244             :                             aPolygon,
     245         207 :                             aColor));
     246             :                     }
     247             :                     else
     248             :                     {
     249             :                         // create filled polygon primitive
     250          33 :                         const basegfx::B2DVector aLineWidthOffset(((nWidth + 1) * 0.5) * aPerpendicular);
     251             : 
     252          33 :                         aPolygon.append( aTmpStart );
     253          33 :                         aPolygon.append( aTmpEnd );
     254             : 
     255             :                         basegfx::B2DPolyPolygon aDashed =
     256          66 :                             svtools::ApplyLineDashing(aPolygon, getStyle(), mfPatternScale*10.0);
     257             : 
     258         112 :                         for (sal_uInt32 i = 0; i < aDashed.count(); i++ )
     259             :                         {
     260          79 :                             basegfx::B2DPolygon aDash = aDashed.getB2DPolygon( i );
     261         158 :                             basegfx::B2DPoint aDashStart = aDash.getB2DPoint( 0 );
     262         158 :                             basegfx::B2DPoint aDashEnd = aDash.getB2DPoint( aDash.count() - 1 );
     263             : 
     264         158 :                             basegfx::B2DPolygon aDashPolygon;
     265          79 :                             aDashPolygon.append( aDashStart + aLineWidthOffset );
     266          79 :                             aDashPolygon.append( aDashEnd + aLineWidthOffset );
     267          79 :                             aDashPolygon.append( aDashEnd - aLineWidthOffset );
     268          79 :                             aDashPolygon.append( aDashStart - aLineWidthOffset );
     269          79 :                             aDashPolygon.setClosed( true );
     270             : 
     271             :                             basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon(
     272         158 :                                 aDashPolygon, aClipRegion, true, false );
     273             : 
     274          79 :                             if ( aClipped.count() )
     275          76 :                                 aDashed.setB2DPolygon( i, aClipped.getB2DPolygon( 0 ) );
     276          79 :                         }
     277             : 
     278          33 :                         sal_uInt32 n = aDashed.count();
     279          33 :                         xRetval.realloc(n);
     280         112 :                         for (sal_uInt32 i = 0; i < n; ++i)
     281             :                         {
     282          79 :                             basegfx::B2DPolygon aDash = aDashed.getB2DPolygon(i);
     283          79 :                             if (bIsHairline)
     284             :                             {
     285             :                                 // Convert a rectanglar polygon into a line.
     286           0 :                                 basegfx::B2DPolygon aDash2;
     287           0 :                                 basegfx::B2DRange aRange = aDash.getB2DRange();
     288           0 :                                 aDash2.append(basegfx::B2DPoint(aRange.getMinX(), aRange.getMinY()));
     289           0 :                                 aDash2.append(basegfx::B2DPoint(aRange.getMaxX(), aRange.getMinY()));
     290           0 :                                 xRetval[i] = Primitive2DReference(
     291           0 :                                     new PolygonHairlinePrimitive2D(aDash2, aColor));
     292             :                             }
     293             :                             else
     294             :                             {
     295         158 :                                 xRetval[i] = Primitive2DReference(
     296         237 :                                     new PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aDash), aColor));
     297             :                             }
     298         112 :                         }
     299         102 :                     }
     300         174 :                 }
     301             :             }
     302             : 
     303         174 :             return xRetval;
     304             :         }
     305             : 
     306       12637 :         BorderLinePrimitive2D::BorderLinePrimitive2D(
     307             :             const basegfx::B2DPoint& rStart,
     308             :             const basegfx::B2DPoint& rEnd,
     309             :             double fLeftWidth,
     310             :             double fDistance,
     311             :             double fRightWidth,
     312             :             double fExtendLeftStart,
     313             :             double fExtendLeftEnd,
     314             :             double fExtendRightStart,
     315             :             double fExtendRightEnd,
     316             :             const basegfx::BColor& rRGBColorRight,
     317             :             const basegfx::BColor& rRGBColorLeft,
     318             :             const basegfx::BColor& rRGBColorGap,
     319             :             bool bHasGapColor,
     320             :             const short nStyle,
     321             :             double fPatternScale)
     322             :         :   BufferedDecompositionPrimitive2D(),
     323             :             maStart(rStart),
     324             :             maEnd(rEnd),
     325             :             mfLeftWidth(fLeftWidth),
     326             :             mfDistance(fDistance),
     327             :             mfRightWidth(fRightWidth),
     328             :             mfExtendLeftStart(fExtendLeftStart),
     329             :             mfExtendLeftEnd(fExtendLeftEnd),
     330             :             mfExtendRightStart(fExtendRightStart),
     331             :             mfExtendRightEnd(fExtendRightEnd),
     332             :             maRGBColorRight(rRGBColorRight),
     333             :             maRGBColorLeft(rRGBColorLeft),
     334             :             maRGBColorGap(rRGBColorGap),
     335             :             mbHasGapColor(bHasGapColor),
     336             :             mnStyle(nStyle),
     337       12637 :             mfPatternScale(fPatternScale)
     338             :         {
     339       12637 :         }
     340             : 
     341           0 :         bool BorderLinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
     342             :         {
     343           0 :             if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
     344             :             {
     345           0 :                 const BorderLinePrimitive2D& rCompare = static_cast<const BorderLinePrimitive2D&>(rPrimitive);
     346             : 
     347           0 :                 return (getStart() == rCompare.getStart()
     348           0 :                     && getEnd() == rCompare.getEnd()
     349           0 :                     && getLeftWidth() == rCompare.getLeftWidth()
     350           0 :                     && getDistance() == rCompare.getDistance()
     351           0 :                     && getRightWidth() == rCompare.getRightWidth()
     352           0 :                     && getExtendLeftStart() == rCompare.getExtendLeftStart()
     353           0 :                     && getExtendLeftEnd() == rCompare.getExtendLeftEnd()
     354           0 :                     && getExtendRightStart() == rCompare.getExtendRightStart()
     355           0 :                     && getExtendRightEnd() == rCompare.getExtendRightEnd()
     356           0 :                     && getRGBColorRight() == rCompare.getRGBColorRight()
     357           0 :                     && getRGBColorLeft() == rCompare.getRGBColorLeft()
     358           0 :                     && getRGBColorGap() == rCompare.getRGBColorGap()
     359           0 :                     && hasGapColor() == rCompare.hasGapColor()
     360           0 :                     && getStyle() == rCompare.getStyle()
     361           0 :                     && getPatternScale() == rCompare.getPatternScale());
     362             :             }
     363             : 
     364           0 :             return false;
     365             :         }
     366             : 
     367             :         // provide unique ID
     368       12563 :         ImplPrimitive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D)
     369             : 
     370             :     } // end of namespace primitive2d
     371             : } // end of namespace drawinglayer
     372             : 
     373             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11