LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/drawinglayer/source/primitive2d - borderlineprimitive2d.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 154 172 89.5 %
Date: 2013-07-09 Functions: 9 10 90.0 %
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       83577 :     static bool lcl_UseHairline(double const fW,
      37             :             basegfx::B2DPoint const& rStart, basegfx::B2DPoint const& rEnd,
      38             :             geometry::ViewInformation2D const& rViewInformation)
      39             :     {
      40       83577 :         basegfx::B2DTuple scale;
      41      167154 :         basegfx::B2DTuple translation;
      42             :         double fRotation;
      43             :         double fShear;
      44       83577 :         rViewInformation.getObjectToViewTransformation().decompose(
      45       83577 :                 scale, translation, fRotation, fShear);
      46             :         double const fScale(
      47       83577 :             (rEnd.getX() - rStart.getX() > rEnd.getY() - rStart.getY())
      48       83577 :                 ? scale.getY() : scale.getX());
      49      167154 :         return (fW * fScale < 0.51);
      50             :     }
      51             : 
      52       75969 :     static double lcl_GetCorrectedWidth(double const fW,
      53             :             basegfx::B2DPoint const& rStart, basegfx::B2DPoint const& rEnd,
      54             :             geometry::ViewInformation2D const& rViewInformation)
      55             :     {
      56       75969 :         return (lcl_UseHairline(fW, rStart, rEnd, rViewInformation)) ? 0.0 : fW;
      57             :     }
      58             : 
      59             :     namespace primitive2d
      60             :     {
      61       22785 :         double BorderLinePrimitive2D::getWidth(
      62             :             geometry::ViewInformation2D const& rViewInformation) const
      63             :         {
      64       22785 :             return lcl_GetCorrectedWidth(mfLeftWidth, getStart(), getEnd(),
      65       22785 :                         rViewInformation)
      66       45570 :                  + lcl_GetCorrectedWidth(mfDistance, getStart(), getEnd(),
      67       22785 :                          rViewInformation)
      68       22785 :                  + lcl_GetCorrectedWidth(mfRightWidth, getStart(), getEnd(),
      69       22785 :                          rViewInformation);
      70             :         }
      71             : 
      72        7595 :         basegfx::B2DPolyPolygon BorderLinePrimitive2D::getClipPolygon(
      73             :             geometry::ViewInformation2D const& rViewInformation) const
      74             :         {
      75        7595 :             basegfx::B2DPolygon clipPolygon;
      76             : 
      77             :             // Get the vectors
      78       15190 :             basegfx::B2DVector aVector( getEnd() - getStart() );
      79        7595 :             aVector.normalize();
      80       15190 :             const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
      81             : 
      82             :             // Get the points
      83        7595 :             const double fWidth(getWidth(rViewInformation));
      84             :             const basegfx::B2DVector aLeftOff(
      85       15190 :                     aPerpendicular * (-0.5 * std::max(fWidth, 1.0)));
      86             :             const basegfx::B2DVector aRightOff(
      87       15190 :                     aPerpendicular * (0.5 * std::max(fWidth, 1.0)));
      88             : 
      89       15190 :             const basegfx::B2DVector aSLVector( aLeftOff - ( getExtendLeftStart() * aVector ) );
      90        7595 :             clipPolygon.append( basegfx::B2DPoint( getStart() + aSLVector * 2.0 ) );
      91             : 
      92        7595 :             clipPolygon.append( getStart( ) );
      93             : 
      94       15190 :             const basegfx::B2DVector aSRVector( aRightOff - ( getExtendRightStart() * aVector ) );
      95        7595 :             clipPolygon.append( basegfx::B2DPoint( getStart() + aSRVector * 2.0 ) );
      96             : 
      97       15190 :             const basegfx::B2DVector aERVector( aRightOff + ( getExtendRightEnd() * aVector ) );
      98        7595 :             clipPolygon.append( basegfx::B2DPoint( getEnd() + aERVector * 2.0 ) );
      99             : 
     100        7595 :             clipPolygon.append( getEnd( ) );
     101             : 
     102       15190 :             const basegfx::B2DVector aELVector( aLeftOff + ( getExtendLeftEnd() * aVector ) );
     103        7595 :             clipPolygon.append( basegfx::B2DPoint( getEnd() + aELVector * 2.0 ) );
     104             : 
     105        7595 :             clipPolygon.setClosed( true );
     106             : 
     107       15190 :             return basegfx::B2DPolyPolygon( clipPolygon );
     108             :         }
     109             : 
     110        7595 :         Primitive2DSequence BorderLinePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
     111             :         {
     112        7595 :             Primitive2DSequence xRetval;
     113             : 
     114        7595 :             if(!getStart().equal(getEnd()) && ( isInsideUsed() || isOutsideUsed() ) )
     115             :             {
     116             :                 // get data and vectors
     117        7595 :                 const double fWidth(getWidth(rViewInformation));
     118        7595 :                 basegfx::B2DVector aVector(getEnd() - getStart());
     119        7595 :                 aVector.normalize();
     120       15190 :                 const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
     121             : 
     122             :                 const basegfx::B2DPolyPolygon& aClipRegion =
     123       15190 :                     getClipPolygon(rViewInformation);
     124             : 
     125        7595 :                 if(isOutsideUsed() && isInsideUsed())
     126             :                 {
     127          13 :                     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          13 :                     xRetval.realloc(2);
     131          13 :                     sal_uInt32 nInsert(0);
     132             : 
     133          13 :                     basegfx::B2DPolygon aGap;
     134             : 
     135             :                     {
     136             :                         // create geometry for left
     137          13 :                         const basegfx::B2DVector aLeftOff(aPerpendicular * (0.5 * (lcl_GetCorrectedWidth(mfLeftWidth, getStart(), getEnd(), rViewInformation) - fWidth + 1)));
     138          26 :                         const basegfx::B2DPoint aTmpStart(getStart() + aLeftOff - ( fExt * aVector));
     139          26 :                         const basegfx::B2DPoint aTmpEnd(getEnd() + aLeftOff + ( fExt * aVector));
     140          26 :                         basegfx::B2DPolygon aLeft;
     141             : 
     142          26 :                         if (lcl_UseHairline(mfLeftWidth, getStart(), getEnd(),
     143          13 :                                     rViewInformation))
     144             :                         {
     145             :                             // create hairline primitive
     146          10 :                             aLeft.append(aTmpStart);
     147          10 :                             aLeft.append(aTmpEnd);
     148             : 
     149             :                             basegfx::B2DPolyPolygon const aClipped =
     150             :                                 basegfx::tools::clipPolygonOnPolyPolygon(
     151          10 :                                     aLeft, aClipRegion, true, true);
     152             : 
     153          20 :                             xRetval[nInsert++] =
     154             :                                 new PolyPolygonHairlinePrimitive2D(
     155             :                                     aClipped,
     156          20 :                                     getRGBColorLeft());
     157             : 
     158          10 :                             aGap.append( getStart() - getExtendLeftStart() * aVector );
     159          10 :                             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           3 :                             const basegfx::B2DVector aLineWidthOffset((lcl_GetCorrectedWidth(mfLeftWidth, getStart(), getEnd(), rViewInformation) * 0.5) * aPerpendicular);
     168             : 
     169           3 :                             aLeft.append(aTmpStart + aLineWidthOffset);
     170           3 :                             aLeft.append(aTmpEnd + aLineWidthOffset);
     171           3 :                             aLeft.append(aTmpEnd - aLineWidthOffset);
     172           3 :                             aLeft.append(aTmpStart - aLineWidthOffset);
     173           3 :                             aLeft.setClosed(true);
     174             : 
     175             :                             basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon(
     176           6 :                                     aLeft, aClipRegion, true, false );
     177             : 
     178           3 :                             aGap.append( aTmpStart + aLineWidthOffset );
     179           3 :                             aGap.append( aTmpEnd + aLineWidthOffset );
     180             : 
     181           6 :                             xRetval[nInsert++] = Primitive2DReference(new PolyPolygonColorPrimitive2D(
     182           9 :                                 aClipped, getRGBColorLeft()));
     183          13 :                         }
     184             :                     }
     185             : 
     186             :                     {
     187             :                         // create geometry for right
     188          13 :                         const basegfx::B2DVector aRightOff(aPerpendicular * (0.5 * (fWidth - lcl_GetCorrectedWidth(mfRightWidth, getStart(), getEnd(), rViewInformation) + 1)));
     189          26 :                         const basegfx::B2DPoint aTmpStart(getStart() + aRightOff - ( fExt * aVector));
     190          26 :                         const basegfx::B2DPoint aTmpEnd(getEnd() + aRightOff + ( fExt * aVector));
     191          26 :                         basegfx::B2DPolygon aRight;
     192             : 
     193          26 :                         if (lcl_UseHairline(mfRightWidth, getStart(), getEnd(),
     194          13 :                                     rViewInformation))
     195             :                         {
     196             :                             // create hairline primitive
     197          10 :                             aRight.append(aTmpStart);
     198          10 :                             aRight.append(aTmpEnd);
     199             : 
     200             :                             basegfx::B2DPolyPolygon const aClipped =
     201             :                                 basegfx::tools::clipPolygonOnPolyPolygon(
     202          10 :                                     aRight, aClipRegion, true, true);
     203             : 
     204          20 :                             xRetval[nInsert++] =
     205             :                                 new PolyPolygonHairlinePrimitive2D(
     206             :                                     aClipped,
     207          20 :                                     getRGBColorRight());
     208             : 
     209          10 :                             aGap.append( getStart() - getExtendRightStart() * aVector );
     210          10 :                             aGap.append( getEnd() + getExtendRightEnd() * aVector );
     211             :                         }
     212             :                         else
     213             :                         {
     214             :                             // create filled polygon primitive
     215           3 :                             const basegfx::B2DVector aLineWidthOffset((lcl_GetCorrectedWidth(mfRightWidth, getStart(), getEnd(), rViewInformation) * 0.5) * aPerpendicular);
     216             : 
     217           3 :                             aRight.append(aTmpStart + aLineWidthOffset);
     218           3 :                             aRight.append(aTmpEnd + aLineWidthOffset);
     219           3 :                             aRight.append(aTmpEnd - aLineWidthOffset);
     220           3 :                             aRight.append(aTmpStart - aLineWidthOffset);
     221           3 :                             aRight.setClosed(true);
     222             : 
     223             :                             basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon(
     224           6 :                                     aRight, aClipRegion, true, false );
     225             : 
     226           6 :                             xRetval[nInsert++] = Primitive2DReference(new PolyPolygonColorPrimitive2D(
     227           6 :                                 aClipped, getRGBColorRight()));
     228             : 
     229           3 :                             aGap.append( aTmpEnd - aLineWidthOffset );
     230           6 :                             aGap.append( aTmpStart - aLineWidthOffset );
     231          13 :                         }
     232             :                     }
     233             : 
     234          13 :                     if (hasGapColor() && aGap.count() == 4)
     235             :                     {
     236           3 :                         xRetval.realloc( xRetval.getLength() + 1 );
     237             :                         // create geometry for filled gap
     238           3 :                         aGap.setClosed( true );
     239             : 
     240             :                         basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon(
     241           3 :                                 aGap, aClipRegion, true, false );
     242             : 
     243           6 :                         xRetval[nInsert++] = Primitive2DReference( new PolyPolygonColorPrimitive2D(
     244           9 :                               aClipped, getRGBColorGap() ) );
     245          13 :                     }
     246             :                 }
     247             :                 else
     248             :                 {
     249             :                     // single line, create geometry
     250        7582 :                     basegfx::B2DPolygon aPolygon;
     251        7582 :                     const double fExt = getWidth(rViewInformation);  // Extend a lot: it'll be clipped after
     252       15164 :                     const basegfx::B2DPoint aTmpStart(getStart() - (fExt * aVector));
     253       15164 :                     const basegfx::B2DPoint aTmpEnd(getEnd() + (fExt * aVector));
     254        7582 :                     xRetval.realloc(1);
     255             : 
     256             :                     // Get which is the line to show
     257        7582 :                     bool bIsSolidline = isSolidLine();
     258        7582 :                     double nWidth = getLeftWidth();
     259       15164 :                     basegfx::BColor aColor = getRGBColorLeft();
     260        7582 :                     if ( basegfx::fTools::equal( 0.0, mfLeftWidth ) )
     261             :                     {
     262         284 :                         nWidth = getRightWidth();
     263         284 :                         aColor = getRGBColorRight();
     264             :                     }
     265             :                     bool const bIsHairline = lcl_UseHairline(
     266        7582 :                             nWidth, getStart(), getEnd(), rViewInformation);
     267             :                     nWidth = lcl_GetCorrectedWidth(nWidth,
     268        7582 :                                 getStart(), getEnd(), rViewInformation);
     269             : 
     270        7582 :                     if(bIsHairline && bIsSolidline)
     271             :                     {
     272             :                         // create hairline primitive
     273        6887 :                         aPolygon.append( getStart() );
     274        6887 :                         aPolygon.append( getEnd() );
     275             : 
     276       13774 :                         xRetval[0] = Primitive2DReference(new PolygonHairlinePrimitive2D(
     277             :                             aPolygon,
     278       20661 :                             aColor));
     279             :                     }
     280             :                     else
     281             :                     {
     282             :                         // create filled polygon primitive
     283         695 :                         const basegfx::B2DVector aLineWidthOffset(((nWidth + 1) * 0.5) * aPerpendicular);
     284        1390 :                         basegfx::B2DVector aScale( rViewInformation.getInverseObjectToViewTransformation() * aVector );
     285             : 
     286         695 :                         aPolygon.append( aTmpStart );
     287         695 :                         aPolygon.append( aTmpEnd );
     288             : 
     289             :                         basegfx::B2DPolyPolygon aDashed = svtools::ApplyLineDashing(
     290        1390 :                                aPolygon, getStyle(), MAP_PIXEL, aScale.getLength() );
     291        1874 :                         for (sal_uInt32 i = 0; i < aDashed.count(); i++ )
     292             :                         {
     293        1179 :                             basegfx::B2DPolygon aDash = aDashed.getB2DPolygon( i );
     294        2358 :                             basegfx::B2DPoint aDashStart = aDash.getB2DPoint( 0 );
     295        2358 :                             basegfx::B2DPoint aDashEnd = aDash.getB2DPoint( aDash.count() - 1 );
     296             : 
     297        2358 :                             basegfx::B2DPolygon aDashPolygon;
     298        1179 :                             aDashPolygon.append( aDashStart + aLineWidthOffset );
     299        1179 :                             aDashPolygon.append( aDashEnd + aLineWidthOffset );
     300        1179 :                             aDashPolygon.append( aDashEnd - aLineWidthOffset );
     301        1179 :                             aDashPolygon.append( aDashStart - aLineWidthOffset );
     302        1179 :                             aDashPolygon.setClosed( true );
     303             : 
     304             :                             basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon(
     305        2358 :                                 aDashPolygon, aClipRegion, true, false );
     306             : 
     307        1179 :                             if ( aClipped.count() )
     308        1169 :                                 aDashed.setB2DPolygon( i, aClipped.getB2DPolygon( 0 ) );
     309        1179 :                         }
     310             : 
     311        1390 :                         xRetval[0] = Primitive2DReference(new PolyPolygonColorPrimitive2D(
     312        2780 :                                 basegfx::B2DPolyPolygon( aDashed ), aColor));
     313        7582 :                     }
     314        7595 :                 }
     315             :             }
     316             : 
     317        7595 :             return xRetval;
     318             :         }
     319             : 
     320        7595 :         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        7595 :             mnStyle(nStyle)
     350             :         {
     351        7595 :         }
     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        7595 :         ImplPrimitive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D)
     380             : 
     381             :     } // end of namespace primitive2d
     382         408 : } // end of namespace drawinglayer
     383             : 
     384             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10