LCOV - code coverage report
Current view: top level - drawinglayer/source/primitive2d - borderlineprimitive2d.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 145 172 84.3 %
Date: 2014-11-03 Functions: 12 13 92.3 %
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         200 : void moveLine(basegfx::B2DPolygon& rPoly, double fGap, const basegfx::B2DVector& rVector)
      36             : {
      37         200 :     if (basegfx::fTools::equalZero(rVector.getX()))
      38             :     {
      39          92 :         basegfx::B2DHomMatrix aMat(1, 0, fGap, 0, 1, 0);
      40          92 :         rPoly.transform(aMat);
      41             :     }
      42         108 :     else if (basegfx::fTools::equalZero(rVector.getY()))
      43             :     {
      44         108 :         basegfx::B2DHomMatrix aMat(1, 0, 0, 0, 1, fGap);
      45         108 :         rPoly.transform(aMat);
      46             :     }
      47         200 : }
      48             : 
      49          22 : 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          22 :     basegfx::B2DPolygon aPolygon;
      54          22 :     aPolygon.append(rStart);
      55          22 :     aPolygon.append(rEnd);
      56          22 :     moveLine(aPolygon, fGap, rVector);
      57             : 
      58          22 :     return primitive2d::Primitive2DReference(new primitive2d::PolygonHairlinePrimitive2D(aPolygon, rColor));
      59             : }
      60             : 
      61         178 : 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         178 :     const basegfx::B2DVector aPerpendicular = basegfx::getPerpendicular(rVector);
      66         356 :     const basegfx::B2DVector aLineWidthOffset = ((fLineWidth + 1.0) * 0.5) * aPerpendicular;
      67             : 
      68         356 :     basegfx::B2DPolygon aPolygon;
      69         178 :     aPolygon.append(rStart + aLineWidthOffset);
      70         178 :     aPolygon.append(rEnd + aLineWidthOffset);
      71         178 :     aPolygon.append(rEnd - aLineWidthOffset);
      72         178 :     aPolygon.append(rStart - aLineWidthOffset);
      73         178 :     aPolygon.setClosed(true);
      74             : 
      75         178 :     moveLine(aPolygon, fGap, rVector);
      76             : 
      77             :     basegfx::B2DPolyPolygon aClipped =
      78         356 :         basegfx::tools::clipPolygonOnPolyPolygon(aPolygon, rClipRegion, true, false);
      79             : 
      80         178 :     if (aClipped.count())
      81         178 :         aPolygon = aClipped.getB2DPolygon(0);
      82             : 
      83             :     return primitive2d::Primitive2DReference(
      84         356 :         new primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aPolygon), rColor));
      85             : }
      86             : 
      87             : }
      88             : 
      89             :     // fdo#49438: heuristic pseudo hack
      90        1472 :     static bool lcl_UseHairline(double const fW,
      91             :             basegfx::B2DPoint const& rStart, basegfx::B2DPoint const& rEnd,
      92             :             geometry::ViewInformation2D const& rViewInformation)
      93             :     {
      94        1472 :         basegfx::B2DTuple scale;
      95        2944 :         basegfx::B2DTuple translation;
      96             :         double fRotation;
      97             :         double fShear;
      98        1472 :         rViewInformation.getObjectToViewTransformation().decompose(
      99        1472 :                 scale, translation, fRotation, fShear);
     100             :         double const fScale(
     101        1472 :             (rEnd.getX() - rStart.getX() > rEnd.getY() - rStart.getY())
     102        1472 :                 ? scale.getY() : scale.getX());
     103        2944 :         return (fW * fScale < 0.51);
     104             :     }
     105             : 
     106        1188 :     static double lcl_GetCorrectedWidth(double const fW,
     107             :             basegfx::B2DPoint const& rStart, basegfx::B2DPoint const& rEnd,
     108             :             geometry::ViewInformation2D const& rViewInformation)
     109             :     {
     110        1188 :         return (lcl_UseHairline(fW, rStart, rEnd, rViewInformation)) ? 0.0 : fW;
     111             :     }
     112             : 
     113             :     namespace primitive2d
     114             :     {
     115         368 :         double BorderLinePrimitive2D::getWidth(
     116             :             geometry::ViewInformation2D const& rViewInformation) const
     117             :         {
     118         368 :             return lcl_GetCorrectedWidth(mfLeftWidth, getStart(), getEnd(),
     119         368 :                         rViewInformation)
     120         736 :                  + lcl_GetCorrectedWidth(mfDistance, getStart(), getEnd(),
     121         368 :                          rViewInformation)
     122         368 :                  + lcl_GetCorrectedWidth(mfRightWidth, getStart(), getEnd(),
     123         368 :                          rViewInformation);
     124             :         }
     125             : 
     126         184 :         basegfx::B2DPolyPolygon BorderLinePrimitive2D::getClipPolygon(
     127             :             geometry::ViewInformation2D const& rViewInformation) const
     128             :         {
     129         184 :             basegfx::B2DPolygon clipPolygon;
     130             : 
     131             :             // Get the vectors
     132         368 :             basegfx::B2DVector aVector( getEnd() - getStart() );
     133         184 :             aVector.normalize();
     134         368 :             const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
     135             : 
     136             :             // Get the points
     137         184 :             const double fWidth(getWidth(rViewInformation));
     138             :             const basegfx::B2DVector aLeftOff(
     139         368 :                     aPerpendicular * (-0.5 * std::max(fWidth, 1.0)));
     140             :             const basegfx::B2DVector aRightOff(
     141         368 :                     aPerpendicular * (0.5 * std::max(fWidth, 1.0)));
     142             : 
     143         368 :             const basegfx::B2DVector aSLVector( aLeftOff - ( getExtendLeftStart() * aVector ) );
     144         184 :             clipPolygon.append( basegfx::B2DPoint( getStart() + aSLVector * 2.0 ) );
     145             : 
     146         184 :             clipPolygon.append( getStart( ) );
     147             : 
     148         368 :             const basegfx::B2DVector aSRVector( aRightOff - ( getExtendRightStart() * aVector ) );
     149         184 :             clipPolygon.append( basegfx::B2DPoint( getStart() + aSRVector * 2.0 ) );
     150             : 
     151         368 :             const basegfx::B2DVector aERVector( aRightOff + ( getExtendRightEnd() * aVector ) );
     152         184 :             clipPolygon.append( basegfx::B2DPoint( getEnd() + aERVector * 2.0 ) );
     153             : 
     154         184 :             clipPolygon.append( getEnd( ) );
     155             : 
     156         368 :             const basegfx::B2DVector aELVector( aLeftOff + ( getExtendLeftEnd() * aVector ) );
     157         184 :             clipPolygon.append( basegfx::B2DPoint( getEnd() + aELVector * 2.0 ) );
     158             : 
     159         184 :             clipPolygon.setClosed( true );
     160             : 
     161         368 :             return basegfx::B2DPolyPolygon( clipPolygon );
     162             :         }
     163             : 
     164         184 :         Primitive2DSequence BorderLinePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
     165             :         {
     166         184 :             Primitive2DSequence xRetval;
     167             : 
     168         184 :             if(!getStart().equal(getEnd()) && ( isInsideUsed() || isOutsideUsed() ) )
     169             :             {
     170             :                 // get data and vectors
     171         184 :                 basegfx::B2DVector aVector(getEnd() - getStart());
     172         184 :                 aVector.normalize();
     173         368 :                 const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
     174             : 
     175             :                 const basegfx::B2DPolyPolygon& aClipRegion =
     176         368 :                     getClipPolygon(rViewInformation);
     177             : 
     178         184 :                 if(isOutsideUsed() && isInsideUsed())
     179             :                 {
     180         100 :                     const double fExt = getWidth(rViewInformation);  // Extend a lot: it'll be clipped later.
     181         100 :                     const basegfx::B2DPoint aTmpStart(getStart() - (fExt * aVector));
     182         200 :                     const basegfx::B2DPoint aTmpEnd(getEnd() + (fExt * aVector));
     183             : 
     184         100 :                     xRetval.realloc(2);
     185             : 
     186         100 :                     double fLeftWidth = getLeftWidth();
     187         100 :                     bool bLeftHairline = lcl_UseHairline(fLeftWidth, getStart(), getEnd(), rViewInformation);
     188         100 :                     if (bLeftHairline)
     189           8 :                         fLeftWidth = 0.0;
     190             : 
     191         100 :                     double fRightWidth = getRightWidth();
     192         100 :                     bool bRightHairline = lcl_UseHairline(fRightWidth, getStart(), getEnd(), rViewInformation);
     193         100 :                     if (bRightHairline)
     194          14 :                         fRightWidth = 0.0;
     195             : 
     196             :                     // "inside" line
     197             : 
     198         100 :                     if (bLeftHairline)
     199          16 :                         xRetval[0] = makeHairLinePrimitive(
     200          16 :                             getStart(), getEnd(), aVector, getRGBColorLeft(), 0.0);
     201             :                     else
     202         276 :                         xRetval[0] = makeSolidLinePrimitive(
     203         184 :                             aClipRegion, aTmpStart, aTmpEnd, aVector, getRGBColorLeft(), fLeftWidth, -fLeftWidth/2.0);
     204             : 
     205             :                     // "outside" line
     206             : 
     207         100 :                     if (bRightHairline)
     208          42 :                         xRetval[1] = makeHairLinePrimitive(
     209          28 :                             getStart(), getEnd(), aVector, getRGBColorRight(), fLeftWidth+mfDistance);
     210             :                     else
     211         344 :                         xRetval[1] = makeSolidLinePrimitive(
     212         358 :                             aClipRegion, aTmpStart, aTmpEnd, aVector, getRGBColorRight(), fRightWidth, mfDistance+fRightWidth/2.0);
     213             :                 }
     214             :                 else
     215             :                 {
     216             :                     // single line, create geometry
     217          84 :                     basegfx::B2DPolygon aPolygon;
     218          84 :                     const double fExt = getWidth(rViewInformation);  // Extend a lot: it'll be clipped after
     219         168 :                     const basegfx::B2DPoint aTmpStart(getStart() - (fExt * aVector));
     220         168 :                     const basegfx::B2DPoint aTmpEnd(getEnd() + (fExt * aVector));
     221             : 
     222             :                     // Get which is the line to show
     223          84 :                     bool bIsSolidline = isSolidLine();
     224          84 :                     double nWidth = getLeftWidth();
     225         168 :                     basegfx::BColor aColor = getRGBColorLeft();
     226          84 :                     if ( basegfx::fTools::equal( 0.0, mfLeftWidth ) )
     227             :                     {
     228           0 :                         nWidth = getRightWidth();
     229           0 :                         aColor = getRGBColorRight();
     230             :                     }
     231             :                     bool const bIsHairline = lcl_UseHairline(
     232          84 :                             nWidth, getStart(), getEnd(), rViewInformation);
     233             :                     nWidth = lcl_GetCorrectedWidth(nWidth,
     234          84 :                                 getStart(), getEnd(), rViewInformation);
     235             : 
     236          84 :                     if(bIsHairline && bIsSolidline)
     237             :                     {
     238             :                         // create hairline primitive
     239          10 :                         aPolygon.append( getStart() );
     240          10 :                         aPolygon.append( getEnd() );
     241             : 
     242          10 :                         xRetval.realloc(1);
     243          20 :                         xRetval[0] = Primitive2DReference(new PolygonHairlinePrimitive2D(
     244             :                             aPolygon,
     245          30 :                             aColor));
     246             :                     }
     247             :                     else
     248             :                     {
     249             :                         // create filled polygon primitive
     250          74 :                         const basegfx::B2DVector aLineWidthOffset(((nWidth + 1) * 0.5) * aPerpendicular);
     251             : 
     252          74 :                         aPolygon.append( aTmpStart );
     253          74 :                         aPolygon.append( aTmpEnd );
     254             : 
     255             :                         basegfx::B2DPolyPolygon aDashed =
     256         148 :                             svtools::ApplyLineDashing(aPolygon, getStyle(), mfPatternScale*10.0);
     257             : 
     258         240 :                         for (sal_uInt32 i = 0; i < aDashed.count(); i++ )
     259             :                         {
     260         166 :                             basegfx::B2DPolygon aDash = aDashed.getB2DPolygon( i );
     261         332 :                             basegfx::B2DPoint aDashStart = aDash.getB2DPoint( 0 );
     262         332 :                             basegfx::B2DPoint aDashEnd = aDash.getB2DPoint( aDash.count() - 1 );
     263             : 
     264         332 :                             basegfx::B2DPolygon aDashPolygon;
     265         166 :                             aDashPolygon.append( aDashStart + aLineWidthOffset );
     266         166 :                             aDashPolygon.append( aDashEnd + aLineWidthOffset );
     267         166 :                             aDashPolygon.append( aDashEnd - aLineWidthOffset );
     268         166 :                             aDashPolygon.append( aDashStart - aLineWidthOffset );
     269         166 :                             aDashPolygon.setClosed( true );
     270             : 
     271             :                             basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon(
     272         332 :                                 aDashPolygon, aClipRegion, true, false );
     273             : 
     274         166 :                             if ( aClipped.count() )
     275         160 :                                 aDashed.setB2DPolygon( i, aClipped.getB2DPolygon( 0 ) );
     276         166 :                         }
     277             : 
     278          74 :                         sal_uInt32 n = aDashed.count();
     279          74 :                         xRetval.realloc(n);
     280         240 :                         for (sal_uInt32 i = 0; i < n; ++i)
     281             :                         {
     282         166 :                             basegfx::B2DPolygon aDash = aDashed.getB2DPolygon(i);
     283         166 :                             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         332 :                                 xRetval[i] = Primitive2DReference(
     296         498 :                                     new PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aDash), aColor));
     297             :                             }
     298         240 :                         }
     299          84 :                     }
     300         184 :                 }
     301             :             }
     302             : 
     303         184 :             return xRetval;
     304             :         }
     305             : 
     306       18031 :         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       18031 :             mfPatternScale(fPatternScale)
     338             :         {
     339       18031 :         }
     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       17931 :         ImplPrimitive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D)
     369             : 
     370             :     } // end of namespace primitive2d
     371        1143 : } // end of namespace drawinglayer
     372             : 
     373             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10