borderline: correct problems with border display

Borderline display with direct paint and with primitive direct
paint has quite some errors in the current state. Started to
unify usages, check deeper with creation/usage.

borderline: deep changes to BorderLine

Found basic error in determining the offset values
for BorderLinePrimitive creation, these were not
centered on the lines. Corrected that. This makes
it possible to remove the formally used clipping
which seems to have been used to correct that. Also
allows to go back to a 'normal' decomposition that
creates line primitives as expected. That again can
then be painted quite normally.
Also added view-dependent case to the decomposition
to guarantee a gap of one discrete unit (pixel).
Removed the direct painter, too. Checked and corrected
stroking.

borderline: Adapted previews to primitives

Added code to use the primitive representation in
all dialogs and apps using tables. The edit views
use these mostly, so the preview should do that,
too. Currently missing is a good visualization of
diagonals, but this is also true for edit views.
Checked all apps and table usages to not get worse

borderline: correct line dash visualization

When a dashed line is used, a factor of 10.0 was applied in the
original coded, added that. Also the orientation of vertical
borders was inverted since it was simpler to exchange Start/End,
but this also mirrors the line dash visualisation, corrected that

Change-Id: I4c1b380a76cb37389fab1259a53fb7cc9da982d1
e95e246d5563360617a2a2213e4d5ec7d0e736b9
62369b4de58fb0264aeb710ec6983ceddca5701d
77418cc6c84ebb0632f8c3448976e82ce612d6b6
b4eb28dc86ce05eb89b26517167305b994158ef8
borderline: adapt cppunittest and clang
This commit is contained in:
Armin Le Grand 2017-07-04 16:28:58 +02:00
parent fc55711f01
commit f65cbae894
16 changed files with 505 additions and 953 deletions

View File

@ -179,7 +179,6 @@ bool FpComparison::ignore(FunctionDecl* function)
|| dc.Function("create2DDecomposition").Class("ScenePrimitive2D").Namespace("primitive2d").Namespace("drawinglayer").GlobalNamespace() || dc.Function("create2DDecomposition").Class("ScenePrimitive2D").Namespace("primitive2d").Namespace("drawinglayer").GlobalNamespace()
|| dc.Function("createAtom").Class("SvgLinearGradientPrimitive2D").Namespace("primitive2d").Namespace("drawinglayer").GlobalNamespace() || dc.Function("createAtom").Class("SvgLinearGradientPrimitive2D").Namespace("primitive2d").Namespace("drawinglayer").GlobalNamespace()
|| dc.Function("createAtom").Class("SvgRadialGradientPrimitive2D").Namespace("primitive2d").Namespace("drawinglayer").GlobalNamespace() || dc.Function("createAtom").Class("SvgRadialGradientPrimitive2D").Namespace("primitive2d").Namespace("drawinglayer").GlobalNamespace()
|| dc.Function("tryDrawBorderLinePrimitive2DDirect").Class("VclPixelProcessor2D").Namespace("processor2d").Namespace("drawinglayer").GlobalNamespace()
|| dc.Function("FoldConstantsBinaryNode").Class("SbiExprNode").GlobalNamespace() || dc.Function("FoldConstantsBinaryNode").Class("SbiExprNode").GlobalNamespace()
|| dc.Function("Format").Class("SbxValue").GlobalNamespace() || dc.Function("Format").Class("SbxValue").GlobalNamespace()
|| dc.Function("Compare").Class("SbxValue").GlobalNamespace() || dc.Function("Compare").Class("SbxValue").GlobalNamespace()

View File

@ -67,7 +67,6 @@ $(eval $(call gb_Library_add_exception_objects,drawinglayer,\
drawinglayer/source/primitive2d/baseprimitive2d \ drawinglayer/source/primitive2d/baseprimitive2d \
drawinglayer/source/primitive2d/bitmapprimitive2d \ drawinglayer/source/primitive2d/bitmapprimitive2d \
drawinglayer/source/primitive2d/borderlineprimitive2d \ drawinglayer/source/primitive2d/borderlineprimitive2d \
drawinglayer/source/primitive2d/clippedborderlineprimitive2d \
drawinglayer/source/primitive2d/controlprimitive2d \ drawinglayer/source/primitive2d/controlprimitive2d \
drawinglayer/source/primitive2d/cropprimitive2d \ drawinglayer/source/primitive2d/cropprimitive2d \
drawinglayer/source/primitive2d/discretebitmapprimitive2d \ drawinglayer/source/primitive2d/discretebitmapprimitive2d \

View File

@ -17,6 +17,7 @@
#include <drawinglayer/geometry/viewinformation2d.hxx> #include <drawinglayer/geometry/viewinformation2d.hxx>
#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx> #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
#include <drawinglayer/processor2d/baseprocessor2d.hxx> #include <drawinglayer/processor2d/baseprocessor2d.hxx>
#include <drawinglayer/processor2d/processorfromoutputdevice.hxx> #include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
#include <rtl/ref.hxx> #include <rtl/ref.hxx>
@ -70,17 +71,15 @@ void DrawinglayerBorderTest::testDoubleDecompositionSolid()
// Make sure it results in two borders as it's a double one. // Make sure it results in two borders as it's a double one.
CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), aContainer.size()); CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), aContainer.size());
// Get the inside line. // Get the inside line, now a PolygonStrokePrimitive2D
auto pInside = dynamic_cast<const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D*>(aContainer[0].get()); auto pInside = dynamic_cast<const drawinglayer::primitive2d::PolygonStrokePrimitive2D*>(aContainer[0].get());
CPPUNIT_ASSERT(pInside); CPPUNIT_ASSERT(pInside);
// Make sure the inside line's height is fLeftWidth. // Make sure the inside line's height is fLeftWidth.
const basegfx::B2DPolyPolygon& rPolyPolygon = pInside->getB2DPolyPolygon(); const double fLineWidthFromDecompose = pInside->getLineAttribute().getWidth();
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(1), rPolyPolygon.count());
const basegfx::B2DPolygon& rPolygon = rPolyPolygon.getB2DPolygon(0);
const basegfx::B2DRange& rRange = rPolygon.getB2DRange();
// This was 2.47, i.e. the width of the inner line was 1 unit (in the bugdoc's case: 1 pixel) wider than expected. // This was 2.47, i.e. the width of the inner line was 1 unit (in the bugdoc's case: 1 pixel) wider than expected.
CPPUNIT_ASSERT_DOUBLES_EQUAL(fLeftWidth, rRange.getHeight(), basegfx::fTools::getSmallValue()); CPPUNIT_ASSERT_DOUBLES_EQUAL(fLeftWidth, fLineWidthFromDecompose, basegfx::fTools::getSmallValue());
} }
void DrawinglayerBorderTest::testDoublePixelProcessing() void DrawinglayerBorderTest::testDoublePixelProcessing()
@ -100,7 +99,7 @@ void DrawinglayerBorderTest::testDoublePixelProcessing()
basegfx::B2DPoint aEnd(100, 20); basegfx::B2DPoint aEnd(100, 20);
double const fLeftWidth = 1.47; double const fLeftWidth = 1.47;
double const fDistance = 1.47; double const fDistance = 1.47;
double fRightWidth = 1.47; double const fRightWidth = 1.47;
double const fExtendLeftStart = 0; double const fExtendLeftStart = 0;
double const fExtendLeftEnd = 0; double const fExtendLeftEnd = 0;
double const fExtendRightStart = 0; double const fExtendRightStart = 0;
@ -117,31 +116,33 @@ void DrawinglayerBorderTest::testDoublePixelProcessing()
// Process the primitives. // Process the primitives.
pProcessor->process(aPrimitives); pProcessor->process(aPrimitives);
// Now assert the height of the outer (second) border polygon. // Double line now gets decomposed in Metafile to painting four lines
// with width == 0 in a cross pattern due to real line width being between
// 1.0 and 2.0. Count created lines
aMetaFile.Stop(); aMetaFile.Stop();
aMetaFile.WindStart(); aMetaFile.WindStart();
bool bFirst = true; sal_uInt32 nPolyLineActionCount = 0;
sal_Int32 nHeight = 0;
for (std::size_t nAction = 0; nAction < aMetaFile.GetActionSize(); ++nAction) for (std::size_t nAction = 0; nAction < aMetaFile.GetActionSize(); ++nAction)
{ {
MetaAction* pAction = aMetaFile.GetAction(nAction); MetaAction* pAction = aMetaFile.GetAction(nAction);
if (pAction->GetType() == MetaActionType::POLYPOLYGON)
{
if (bFirst)
{
bFirst = false;
continue;
}
auto pMPPAction = static_cast<MetaPolyPolygonAction*>(pAction); if (MetaActionType::POLYLINE == pAction->GetType())
const tools::PolyPolygon& rPolyPolygon = pMPPAction->GetPolyPolygon(); {
nHeight = rPolyPolygon.GetBoundRect().getHeight(); auto pMPLAction = static_cast<MetaPolyLineAction*>(pAction);
if (0 == pMPLAction->GetLineInfo().GetWidth() && LineStyle::Solid == pMPLAction->GetLineInfo().GetStyle())
{
nPolyLineActionCount++;
}
} }
} }
sal_Int32 nExpectedHeight = std::round(fRightWidth);
// This was 2, and should be 1: if the logical requested width is 1.47, // Check if all eight (2x four) simple lines with width == 0 and
// then that must be 1 px on the screen, not 2. // solid were created
CPPUNIT_ASSERT_EQUAL(nExpectedHeight, nHeight); const sal_uInt32 nExpectedNumPolyLineActions = 8;
CPPUNIT_ASSERT_EQUAL(nExpectedNumPolyLineActions, nPolyLineActionCount);
} }
CPPUNIT_TEST_SUITE_REGISTRATION(DrawinglayerBorderTest); CPPUNIT_TEST_SUITE_REGISTRATION(DrawinglayerBorderTest);

View File

@ -42,284 +42,140 @@ T round(T x)
} }
#endif #endif
namespace drawinglayer { namespace drawinglayer
namespace {
void moveLine(basegfx::B2DPolygon& rPoly, double fGap, const basegfx::B2DVector& rVector)
{ {
if (basegfx::fTools::equalZero(rVector.getX()))
{
basegfx::B2DHomMatrix aMat(1, 0, fGap, 0, 1, 0);
rPoly.transform(aMat);
}
else if (basegfx::fTools::equalZero(rVector.getY()))
{
basegfx::B2DHomMatrix aMat(1, 0, 0, 0, 1, fGap);
rPoly.transform(aMat);
}
}
primitive2d::Primitive2DReference makeHairLinePrimitive(
const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd, const basegfx::B2DVector& rVector,
const basegfx::BColor& rColor, double fGap)
{
basegfx::B2DPolygon aPolygon;
aPolygon.append(rStart);
aPolygon.append(rEnd);
moveLine(aPolygon, fGap, rVector);
return primitive2d::Primitive2DReference(new primitive2d::PolygonHairlinePrimitive2D(aPolygon, rColor));
}
primitive2d::Primitive2DReference makeSolidLinePrimitive(
const basegfx::B2DPolyPolygon& rClipRegion, const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd,
const basegfx::B2DVector& rVector, const basegfx::BColor& rColor, double fLineWidth, double fGap)
{
const basegfx::B2DVector aPerpendicular = basegfx::getPerpendicular(rVector);
const basegfx::B2DVector aLineWidthOffset = (fLineWidth * 0.5) * aPerpendicular;
basegfx::B2DPolygon aPolygon;
aPolygon.append(rStart + aLineWidthOffset);
aPolygon.append(rEnd + aLineWidthOffset);
aPolygon.append(rEnd - aLineWidthOffset);
aPolygon.append(rStart - aLineWidthOffset);
aPolygon.setClosed(true);
moveLine(aPolygon, fGap, rVector);
basegfx::B2DPolyPolygon aClipped =
basegfx::tools::clipPolygonOnPolyPolygon(aPolygon, rClipRegion, true, false);
if (aClipped.count())
aPolygon = aClipped.getB2DPolygon(0);
return primitive2d::Primitive2DReference(
new primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aPolygon), rColor));
}
}
// fdo#49438: heuristic pseudo hack
static bool lcl_UseHairline(double const fW,
basegfx::B2DPoint const& rStart, basegfx::B2DPoint const& rEnd,
geometry::ViewInformation2D const& rViewInformation)
{
basegfx::B2DTuple scale;
basegfx::B2DTuple translation;
double fRotation;
double fShear;
rViewInformation.getObjectToViewTransformation().decompose(
scale, translation, fRotation, fShear);
double const fScale(
(rEnd.getX() - rStart.getX() > rEnd.getY() - rStart.getY())
? scale.getY() : scale.getX());
return (fW * fScale < 0.51);
}
static double lcl_GetCorrectedWidth(double const fW,
basegfx::B2DPoint const& rStart, basegfx::B2DPoint const& rEnd,
geometry::ViewInformation2D const& rViewInformation)
{
return (lcl_UseHairline(fW, rStart, rEnd, rViewInformation)) ? 0.0 : fW;
}
namespace primitive2d namespace primitive2d
{ {
double BorderLinePrimitive2D::getWidth( // helper to add a centered, maybe stroked line primitive to rContainer
geometry::ViewInformation2D const& rViewInformation) const void addPolygonStrokePrimitive2D(
Primitive2DContainer& rContainer,
const basegfx::B2DPoint& rStart,
const basegfx::B2DPoint& rEnd,
const basegfx::BColor& rColor,
double fWidth,
SvxBorderLineStyle aStyle,
double fPatternScale)
{ {
return lcl_GetCorrectedWidth(mfLeftWidth, getStart(), getEnd(), basegfx::B2DPolygon aPolygon;
rViewInformation)
+ lcl_GetCorrectedWidth(mfDistance, getStart(), getEnd(), aPolygon.append(rStart);
rViewInformation) aPolygon.append(rEnd);
+ lcl_GetCorrectedWidth(mfRightWidth, getStart(), getEnd(),
rViewInformation); const attribute::LineAttribute aLineAttribute(rColor, fWidth);
static double fPatScFact(10.0); // 10.0 multiply, see old code
const std::vector<double> aDashing(svtools::GetLineDashing(aStyle, fPatternScale * fPatScFact));
if (aDashing.empty())
{
rContainer.push_back(
new PolygonStrokePrimitive2D(
aPolygon,
aLineAttribute));
}
else
{
const attribute::StrokeAttribute aStrokeAttribute(aDashing);
rContainer.push_back(
new PolygonStrokePrimitive2D(
aPolygon,
aLineAttribute,
aStrokeAttribute));
}
} }
basegfx::B2DPolyPolygon BorderLinePrimitive2D::getClipPolygon( void BorderLinePrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const
geometry::ViewInformation2D const& rViewInformation) const
{ {
basegfx::B2DPolygon clipPolygon; if (!getStart().equal(getEnd()) && (isInsideUsed() || isOutsideUsed()))
// Get the vectors
basegfx::B2DVector aVector( getEnd() - getStart() );
aVector.normalize();
const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
// Get the points
const double fWidth(getWidth(rViewInformation));
const basegfx::B2DVector aLeftOff(
aPerpendicular * (-0.5 * std::max(fWidth, 1.0)));
const basegfx::B2DVector aRightOff(
aPerpendicular * (0.5 * std::max(fWidth, 1.0)));
const basegfx::B2DVector aSLVector( aLeftOff - ( getExtendLeftStart() * aVector ) );
clipPolygon.append( basegfx::B2DPoint( getStart() + aSLVector * 2.0 ) );
clipPolygon.append( getStart( ) );
const basegfx::B2DVector aSRVector( aRightOff - ( getExtendRightStart() * aVector ) );
clipPolygon.append( basegfx::B2DPoint( getStart() + aSRVector * 2.0 ) );
const basegfx::B2DVector aERVector( aRightOff + ( getExtendRightEnd() * aVector ) );
clipPolygon.append( basegfx::B2DPoint( getEnd() + aERVector * 2.0 ) );
clipPolygon.append( getEnd( ) );
const basegfx::B2DVector aELVector( aLeftOff + ( getExtendLeftEnd() * aVector ) );
clipPolygon.append( basegfx::B2DPoint( getEnd() + aELVector * 2.0 ) );
clipPolygon.setClosed( true );
return basegfx::B2DPolyPolygon( clipPolygon );
}
void BorderLinePrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const
{
createDecomposition(rContainer, rViewInformation, false);
}
void BorderLinePrimitive2D::createDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation, bool bPixelCorrection) const
{
if(!getStart().equal(getEnd()) && ( isInsideUsed() || isOutsideUsed() ) )
{ {
// get data and vectors // get data and vectors
basegfx::B2DVector aVector(getEnd() - getStart()); basegfx::B2DVector aVector(getEnd() - getStart());
aVector.normalize(); aVector.normalize();
const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector)); const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
const basegfx::B2DPolyPolygon& aClipRegion = if (isOutsideUsed() && isInsideUsed())
getClipPolygon(rViewInformation);
if(isOutsideUsed() && isInsideUsed())
{ {
const double fExt = getWidth(rViewInformation); // Extend a lot: it'll be clipped later. // double line with gap. Use mfDiscreteDistance (see get2DDecomposition) as distance.
const basegfx::B2DPoint aTmpStart(getStart() - (fExt * aVector)); // That value is prepared to be at least one pixel (discrete unit) so that the
const basegfx::B2DPoint aTmpEnd(getEnd() + (fExt * aVector)); // decomposition is view-dependent in this cases
if (isInsideUsed())
double fLeftWidth = getLeftWidth();
bool bLeftHairline = lcl_UseHairline(fLeftWidth, getStart(), getEnd(), rViewInformation);
if (bLeftHairline)
fLeftWidth = 0.0;
double fRightWidth = getRightWidth();
bool bRightHairline = lcl_UseHairline(fRightWidth, getStart(), getEnd(), rViewInformation);
if (bRightHairline)
fRightWidth = 0.0;
// "inside" line
if (bLeftHairline)
rContainer.push_back(makeHairLinePrimitive(
getStart(), getEnd(), aVector, getRGBColorLeft(), 0.0));
else
{ {
double fWidth = bPixelCorrection ? std::round(fLeftWidth) : fLeftWidth; // inside line (left). Create stroke primitive centered on line width
rContainer.push_back(makeSolidLinePrimitive( const double fDeltaY((mfDiscreteDistance + getLeftWidth()) * 0.5);
aClipRegion, aTmpStart, aTmpEnd, aVector, getRGBColorLeft(), fWidth, -fLeftWidth/2.0)); const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY);
const basegfx::B2DPoint aStart(getStart() - (aVector * getExtendLeftStart()) - aDeltaY);
const basegfx::B2DPoint aEnd(getEnd() + (aVector * getExtendLeftEnd()) - aDeltaY);
addPolygonStrokePrimitive2D(
rContainer,
aStart,
aEnd,
getRGBColorLeft(),
getLeftWidth(),
getStyle(),
getPatternScale());
} }
// "outside" line if (hasGapColor() && isDistanceUsed())
if (bRightHairline)
rContainer.push_back(makeHairLinePrimitive(
getStart(), getEnd(), aVector, getRGBColorRight(), fLeftWidth+mfDistance));
else
{ {
double fWidth = bPixelCorrection ? std::round(fRightWidth) : fRightWidth; // gap (if visible, found no practicval usage).
rContainer.push_back(makeSolidLinePrimitive( // Create stroke primitive on vector with given color
aClipRegion, aTmpStart, aTmpEnd, aVector, getRGBColorRight(), fWidth, mfDistance+fRightWidth/2.0)); addPolygonStrokePrimitive2D(
rContainer,
getStart(),
getEnd(),
getRGBColorGap(),
mfDiscreteDistance,
getStyle(),
getPatternScale());
}
if (isOutsideUsed())
{
// outside line (right). Create stroke primitive centered on line width
const double fDeltaY((mfDiscreteDistance + getRightWidth()) * 0.5);
const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY);
const basegfx::B2DPoint aStart(getStart() - (aVector * getExtendRightStart()) + aDeltaY);
const basegfx::B2DPoint aEnd(getEnd() + (aVector * getExtendRightEnd()) + aDeltaY);
addPolygonStrokePrimitive2D(
rContainer,
aStart,
aEnd,
getRGBColorRight(),
getRightWidth(),
getStyle(),
getPatternScale());
} }
} }
else else if(isInsideUsed())
{ {
// single line, create geometry // single line, only inside values used, no vertical offsets
basegfx::B2DPolygon aPolygon; addPolygonStrokePrimitive2D(
const double fExt = getWidth(rViewInformation); // Extend a lot: it'll be clipped after rContainer,
const basegfx::B2DPoint aTmpStart(getStart() - (fExt * aVector)); getStart(),
const basegfx::B2DPoint aTmpEnd(getEnd() + (fExt * aVector)); getEnd(),
getRGBColorLeft(),
// Get which is the line to show getLeftWidth(),
bool bIsSolidline = mnStyle == SvxBorderLineStyle::SOLID; getStyle(),
double nWidth = getLeftWidth(); getPatternScale());
basegfx::BColor aColor = getRGBColorLeft();
if ( basegfx::fTools::equal( 0.0, mfLeftWidth ) )
{
nWidth = getRightWidth();
aColor = getRGBColorRight();
}
bool const bIsHairline = lcl_UseHairline(
nWidth, getStart(), getEnd(), rViewInformation);
nWidth = lcl_GetCorrectedWidth(nWidth,
getStart(), getEnd(), rViewInformation);
if(bIsHairline && bIsSolidline)
{
// create hairline primitive
aPolygon.append( getStart() );
aPolygon.append( getEnd() );
rContainer.push_back(new PolygonHairlinePrimitive2D(
aPolygon,
aColor));
}
else
{
// create filled polygon primitive
const basegfx::B2DVector aLineWidthOffset(((nWidth + 1) * 0.5) * aPerpendicular);
aPolygon.append( aTmpStart );
aPolygon.append( aTmpEnd );
basegfx::B2DPolyPolygon aDashed =
svtools::ApplyLineDashing(aPolygon, getStyle(), mfPatternScale*10.0);
for (sal_uInt32 i = 0; i < aDashed.count(); i++ )
{
basegfx::B2DPolygon aDash = aDashed.getB2DPolygon( i );
basegfx::B2DPoint aDashStart = aDash.getB2DPoint( 0 );
basegfx::B2DPoint aDashEnd = aDash.getB2DPoint( aDash.count() - 1 );
basegfx::B2DPolygon aDashPolygon;
aDashPolygon.append( aDashStart + aLineWidthOffset );
aDashPolygon.append( aDashEnd + aLineWidthOffset );
aDashPolygon.append( aDashEnd - aLineWidthOffset );
aDashPolygon.append( aDashStart - aLineWidthOffset );
aDashPolygon.setClosed( true );
basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon(
aDashPolygon, aClipRegion, true, false );
if ( aClipped.count() )
aDashed.setB2DPolygon( i, aClipped.getB2DPolygon( 0 ) );
}
sal_uInt32 n = aDashed.count();
for (sal_uInt32 i = 0; i < n; ++i)
{
basegfx::B2DPolygon aDash = aDashed.getB2DPolygon(i);
if (bIsHairline)
{
// Convert a rectangular polygon into a line.
basegfx::B2DPolygon aDash2;
basegfx::B2DRange aRange = aDash.getB2DRange();
aDash2.append(basegfx::B2DPoint(aRange.getMinX(), aRange.getMinY()));
aDash2.append(basegfx::B2DPoint(aRange.getMaxX(), aRange.getMinY()));
rContainer.push_back(
new PolygonHairlinePrimitive2D(aDash2, aColor));
}
else
{
rContainer.push_back(
new PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aDash), aColor));
}
}
}
} }
} }
} }
bool BorderLinePrimitive2D::isHorizontalOrVertical(const geometry::ViewInformation2D& rViewInformation) const
{
if (!getStart().equal(getEnd()))
{
const basegfx::B2DHomMatrix& rOTVT = rViewInformation.getObjectToViewTransformation();
const basegfx::B2DVector aVector(rOTVT * getEnd() - rOTVT * getStart());
return basegfx::fTools::equalZero(aVector.getX()) || basegfx::fTools::equalZero(aVector.getY());
}
return false;
}
BorderLinePrimitive2D::BorderLinePrimitive2D( BorderLinePrimitive2D::BorderLinePrimitive2D(
const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rStart,
const basegfx::B2DPoint& rEnd, const basegfx::B2DPoint& rEnd,
@ -351,7 +207,8 @@ primitive2d::Primitive2DReference makeSolidLinePrimitive(
maRGBColorGap(rRGBColorGap), maRGBColorGap(rRGBColorGap),
mbHasGapColor(bHasGapColor), mbHasGapColor(bHasGapColor),
mnStyle(nStyle), mnStyle(nStyle),
mfPatternScale(fPatternScale) mfPatternScale(fPatternScale),
mfDiscreteDistance(0.0)
{ {
} }
@ -381,6 +238,42 @@ primitive2d::Primitive2DReference makeSolidLinePrimitive(
return false; return false;
} }
void BorderLinePrimitive2D::get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const
{
::osl::MutexGuard aGuard(m_aMutex);
if (!getStart().equal(getEnd()) && isOutsideUsed() && isInsideUsed())
{
// Double line with gap. In this case, we want to be view-dependent.
// Get the current DiscreteUnit, look at X and Y and use the maximum
const basegfx::B2DVector aDiscreteVector(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0));
const double fDiscreteUnit(std::min(fabs(aDiscreteVector.getX()), fabs(aDiscreteVector.getY())));
// When discrete unit is bigger than distance (distance is less than one pixel),
// force distance to one pixel. Or expressed different, do not let the distance
// get smaller than one pixel. This is done for screen rendering and compatibility.
// This can also be done using DiscreteMetricDependentPrimitive2D as base class
// for this class, but specialization is better here for later buffering (only
// do this when 'double line with gap')
const double fNewDiscreteDistance(std::max(fDiscreteUnit, getDistance()));
if (!rtl::math::approxEqual(fNewDiscreteDistance, mfDiscreteDistance))
{
if (!getBuffered2DDecomposition().empty())
{
// conditions of last local decomposition have changed, delete
const_cast< BorderLinePrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DContainer());
}
// remember value for usage in create2DDecomposition
const_cast< BorderLinePrimitive2D* >(this)->mfDiscreteDistance = fNewDiscreteDistance;
}
}
// call base implementation
BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor, rViewInformation);
}
// provide unique ID // provide unique ID
ImplPrimitive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D) ImplPrimitive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D)

View File

@ -1,64 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <drawinglayer/primitive2d/clippedborderlineprimitive2d.hxx>
#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
namespace drawinglayer
{
namespace primitive2d
{
basegfx::B2DPolyPolygon ClippedBorderLinePrimitive2D::getClipPolygon(
SAL_UNUSED_PARAMETER geometry::ViewInformation2D const&) const
{
basegfx::B2DPolyPolygon aPolyPolygon;
aPolyPolygon.append( maIntersection );
return aPolyPolygon;
}
ClippedBorderLinePrimitive2D::ClippedBorderLinePrimitive2D(
const basegfx::B2DPoint& rStart,
const basegfx::B2DPoint& rEnd,
double fLeftWidth,
double fDistance,
double fRightWidth,
const basegfx::B2DPolygon& rIntersection,
const basegfx::BColor& rRGBColorRight,
const basegfx::BColor& rRGBColorLeft,
const basegfx::BColor& rRGBColorGap,
bool bHasGapColor,
SvxBorderLineStyle nStyle,
double fPatternScale)
: BorderLinePrimitive2D( rStart, rEnd, fLeftWidth,fDistance, fRightWidth,
0.0, 0.0, 0.0, 0.0, rRGBColorRight, rRGBColorLeft,
rRGBColorGap, bHasGapColor, nStyle, fPatternScale),
maIntersection( rIntersection )
{
}
bool ClippedBorderLinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
{
if(BorderLinePrimitive2D::operator==(rPrimitive))
{
const ClippedBorderLinePrimitive2D& rCompare = static_cast<const ClippedBorderLinePrimitive2D&>(rPrimitive);
return maIntersection == rCompare.maIntersection;
}
return false;
}
// provide unique ID
ImplPrimitive2DIDBlock(ClippedBorderLinePrimitive2D, PRIMITIVE2D_ID_CLIPPEDBORDERLINEPRIMITIVE2D)
} // namespace primitive2d
} // namespace drawinglayer
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@ -70,34 +70,6 @@ T round(T x)
using namespace com::sun::star; using namespace com::sun::star;
namespace {
basegfx::B2DPolygon makeRectPolygon( double fX, double fY, double fW, double fH )
{
basegfx::B2DPolygon aPoly;
aPoly.append(basegfx::B2DPoint(fX, fY));
aPoly.append(basegfx::B2DPoint(fX+fW, fY));
aPoly.append(basegfx::B2DPoint(fX+fW, fY+fH));
aPoly.append(basegfx::B2DPoint(fX, fY+fH));
aPoly.setClosed(true);
return aPoly;
}
void drawHairLine(
OutputDevice* pOutDev, double fX1, double fY1, double fX2, double fY2,
const basegfx::BColor& rColor )
{
basegfx::B2DPolygon aTarget;
aTarget.append(basegfx::B2DPoint(fX1, fY1));
aTarget.append(basegfx::B2DPoint(fX2, fY2));
pOutDev->SetFillColor();
pOutDev->SetLineColor(Color(rColor));
pOutDev->DrawPolyLine(aTarget);
}
}
namespace drawinglayer namespace drawinglayer
{ {
namespace processor2d namespace processor2d
@ -306,341 +278,6 @@ namespace drawinglayer
return bTryWorked; return bTryWorked;
} }
bool VclPixelProcessor2D::tryDrawBorderLinePrimitive2DDirect(
const drawinglayer::primitive2d::BorderLinePrimitive2D& rSource)
{
const basegfx::B2DPoint& rS = rSource.getStart();
const basegfx::B2DPoint& rE = rSource.getEnd();
double fX1 = rS.getX();
double fY1 = rS.getY();
double fX2 = rE.getX();
double fY2 = rE.getY();
bool bHorizontal = false;
if (fX1 == fX2)
{
// Vertical line.
}
else if (fY1 == fY2)
{
// Horizontal line.
bHorizontal = true;
}
else
// Neither. Bail out.
return false;
switch (rSource.getStyle())
{
case SvxBorderLineStyle::SOLID:
case SvxBorderLineStyle::DOUBLE_THIN:
{
const basegfx::BColor aLineColor =
maBColorModifierStack.getModifiedColor(rSource.getRGBColorLeft());
double nThick = rtl::math::round(rSource.getLeftWidth());
bool bDouble = rSource.getStyle() == SvxBorderLineStyle::DOUBLE_THIN;
basegfx::B2DPolygon aTarget;
if (bHorizontal)
{
// Horizontal line. Draw it as a rectangle.
aTarget = makeRectPolygon(fX1, fY1, fX2-fX1, nThick);
aTarget.transform(maCurrentTransformation);
basegfx::B2DRange aRange = aTarget.getB2DRange();
double fH = aRange.getHeight();
if (bDouble)
{
// Double line
drawHairLine(
mpOutputDevice, aRange.getMinX(), aRange.getMinY()-1.0, aRange.getMaxX(), aRange.getMinY()-1.0,
aLineColor);
drawHairLine(
mpOutputDevice, aRange.getMinX(), aRange.getMinY()+1.0, aRange.getMaxX(), aRange.getMinY()+1.0,
aLineColor);
return true;
}
if (fH <= 1.0)
{
// Draw it as a line.
drawHairLine(
mpOutputDevice, aRange.getMinX(), aRange.getMinY(), aRange.getMaxX(), aRange.getMinY(),
aLineColor);
return true;
}
double fOffset = rtl::math::round(fH/2.0, 0, rtl_math_RoundingMode_Down);
if (fOffset != 0.0)
{
// Move it up a bit to align it vertically centered.
basegfx::B2DHomMatrix aMat;
aMat.set(1, 2, -fOffset);
aTarget.transform(aMat);
}
}
else
{
// Vertical line. Draw it as a rectangle.
aTarget = makeRectPolygon(fX1, fY1, nThick, fY2-fY1);
aTarget.transform(maCurrentTransformation);
basegfx::B2DRange aRange = aTarget.getB2DRange();
double fW = aRange.getWidth();
if (bDouble)
{
// Draw it as a line.
drawHairLine(
mpOutputDevice, aRange.getMinX()-1.0, aRange.getMinY(), aRange.getMinX()-1.0, aRange.getMaxY(),
aLineColor);
drawHairLine(
mpOutputDevice, aRange.getMinX()+1.0, aRange.getMinY(), aRange.getMinX()+1.0, aRange.getMaxY(),
aLineColor);
return true;
}
if (fW <= 1.0)
{
// Draw it as a line.
drawHairLine(
mpOutputDevice, aRange.getMinX(), aRange.getMinY(), aRange.getMinX(), aRange.getMaxY(),
aLineColor);
return true;
}
double fOffset = rtl::math::round(fW/2.0, 0, rtl_math_RoundingMode_Down);
if (fOffset != 0.0)
{
// Move it to the left a bit to center it horizontally.
basegfx::B2DHomMatrix aMat;
aMat.set(0, 2, -fOffset);
aTarget.transform(aMat);
}
}
mpOutputDevice->SetFillColor(Color(aLineColor));
mpOutputDevice->SetLineColor();
mpOutputDevice->DrawPolygon(aTarget);
return true;
}
break;
case SvxBorderLineStyle::DOTTED:
case SvxBorderLineStyle::DASHED:
case SvxBorderLineStyle::DASH_DOT:
case SvxBorderLineStyle::DASH_DOT_DOT:
case SvxBorderLineStyle::FINE_DASHED:
{
std::vector<double> aPattern =
svtools::GetLineDashing(rSource.getStyle(), rSource.getPatternScale()*10.0);
if (aPattern.empty())
// Failed to get pattern values.
return false;
double nThick = rtl::math::round(rSource.getLeftWidth());
const basegfx::BColor aLineColor =
maBColorModifierStack.getModifiedColor(rSource.getRGBColorLeft());
// Transform the current line range before using it for rendering.
basegfx::B2DRange aRange(fX1, fY1, fX2, fY2);
aRange.transform(maCurrentTransformation);
fX1 = aRange.getMinX();
fX2 = aRange.getMaxX();
fY1 = aRange.getMinY();
fY2 = aRange.getMaxY();
basegfx::B2DPolyPolygon aTarget;
if (bHorizontal)
{
// Horizontal line.
if (basegfx::fTools::equalZero(nThick))
{
// Dash line segment too small to draw. Substitute it with a solid line.
drawHairLine(mpOutputDevice, fX1, fY1, fX2, fY1, aLineColor);
return true;
}
// Create a dash unit polygon set.
basegfx::B2DPolyPolygon aDashes;
std::vector<double>::const_iterator it = aPattern.begin(), itEnd = aPattern.end();
for (; it != itEnd; ++it)
aDashes.append(makeRectPolygon(0, 0, *it, nThick));
aDashes.transform(maCurrentTransformation);
rtl::math::setNan(&nThick);
// Pixelize the dash unit. We use the same height for
// all dash polygons.
basegfx::B2DPolyPolygon aDashesPix;
for (sal_uInt32 i = 0, n = aDashes.count(); i < n; ++i)
{
basegfx::B2DPolygon aPoly = aDashes.getB2DPolygon(i);
aRange = aPoly.getB2DRange();
double fW = rtl::math::round(aRange.getWidth());
if (basegfx::fTools::equalZero(fW))
{
// Dash line segment too small to draw. Substitute it with a solid line.
drawHairLine(mpOutputDevice, fX1, fY1, fX2, fY1, aLineColor);
return true;
}
if (rtl::math::isNan(nThick))
nThick = rtl::math::round(aRange.getHeight());
aDashesPix.append(makeRectPolygon(0, 0, fW, nThick));
}
// Make all dash polygons and render them.
double fX = fX1;
bool bLine = true;
sal_uInt32 i = 0, n = aDashesPix.count();
while (fX <= fX2)
{
basegfx::B2DPolygon aPoly = aDashesPix.getB2DPolygon(i);
aRange = aPoly.getB2DRange();
if (bLine)
{
double fBlockW = aRange.getWidth();
if (fX + fBlockW > fX2)
// Clip the right end in case it spills over the range.
fBlockW = fX2 - fX + 1;
double fH = aRange.getHeight();
if (basegfx::fTools::equalZero(fH))
fH = 1.0;
aTarget.append(makeRectPolygon(fX, fY1, fBlockW, fH));
}
bLine = !bLine; // line and blank alternate.
fX += aRange.getWidth();
++i;
if (i >= n)
i = 0;
}
double fOffset = rtl::math::round(nThick/2.0, 0, rtl_math_RoundingMode_Down);
if (fOffset != 0.0)
{
// Move it up a bit to align it vertically centered.
basegfx::B2DHomMatrix aMat;
aMat.set(1, 2, -fOffset);
aTarget.transform(aMat);
}
}
else
{
// Vertical line.
if (basegfx::fTools::equalZero(nThick))
{
// Dash line segment too small to draw. Substitute it with a solid line.
drawHairLine(mpOutputDevice, fX1, fY1, fX1, fY2, aLineColor);
return true;
}
// Create a dash unit polygon set.
basegfx::B2DPolyPolygon aDashes;
std::vector<double>::const_iterator it = aPattern.begin(), itEnd = aPattern.end();
for (; it != itEnd; ++it)
aDashes.append(makeRectPolygon(0, 0, nThick, *it));
aDashes.transform(maCurrentTransformation);
rtl::math::setNan(&nThick);
// Pixelize the dash unit. We use the same width for
// all dash polygons.
basegfx::B2DPolyPolygon aDashesPix;
for (sal_uInt32 i = 0, n = aDashes.count(); i < n; ++i)
{
basegfx::B2DPolygon aPoly = aDashes.getB2DPolygon(i);
aRange = aPoly.getB2DRange();
double fH = rtl::math::round(aRange.getHeight());
if (basegfx::fTools::equalZero(fH))
{
// Dash line segment too small to draw. Substitute it with a solid line.
drawHairLine(mpOutputDevice, fX1, fY1, fX1, fY2, aLineColor);
return true;
}
if (rtl::math::isNan(nThick))
nThick = rtl::math::round(aRange.getWidth());
aDashesPix.append(makeRectPolygon(0, 0, nThick, fH));
}
// Make all dash polygons and render them.
double fY = fY1;
bool bLine = true;
sal_uInt32 i = 0, n = aDashesPix.count();
while (fY <= fY2)
{
basegfx::B2DPolygon aPoly = aDashesPix.getB2DPolygon(i);
aRange = aPoly.getB2DRange();
if (bLine)
{
double fBlockH = aRange.getHeight();
if (fY + fBlockH > fY2)
// Clip the bottom end in case it spills over the range.
fBlockH = fY2 - fY + 1;
double fW = aRange.getWidth();
if (basegfx::fTools::equalZero(fW))
fW = 1.0;
aTarget.append(makeRectPolygon(fX1, fY, fW, fBlockH));
}
bLine = !bLine; // line and blank alternate.
fY += aRange.getHeight();
++i;
if (i >= n)
i = 0;
}
double fOffset = rtl::math::round(nThick/2.0, 0, rtl_math_RoundingMode_Down);
if (fOffset != 0.0)
{
// Move it to the left a bit to center it horizontally.
basegfx::B2DHomMatrix aMat;
aMat.set(0, 2, -fOffset);
aTarget.transform(aMat);
}
}
mpOutputDevice->SetFillColor(Color(aLineColor));
mpOutputDevice->SetLineColor();
mpOutputDevice->DrawPolyPolygon(aTarget);
return true;
}
break;
default:
;
}
return false;
}
void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate) void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
{ {
switch(rCandidate.getPrimitive2DID()) switch(rCandidate.getPrimitive2DID())
@ -1253,28 +890,26 @@ namespace drawinglayer
} }
case PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D: case PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D:
{ {
// process recursively, but turn off anti-aliasing. Border // process recursively, but switch off AntiAliasing for
// lines are always rectangular, and look horrible when // horizontal/vertical lines (*not* diagonal lines).
// the anti-aliasing is enabled. // Checked using AntialiasingFlags::PixelSnapHairline instead,
AntialiasingFlags nAntiAliasing = mpOutputDevice->GetAntialiasing(); // but with AntiAliasing on the display really is too 'ghosty' when
mpOutputDevice->SetAntialiasing(nAntiAliasing & ~AntialiasingFlags::EnableB2dDraw); // using fine stroking. Correct, but 'ghosty'.
const drawinglayer::primitive2d::BorderLinePrimitive2D& rBorder = const drawinglayer::primitive2d::BorderLinePrimitive2D& rBorder =
static_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D&>(rCandidate); static_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D&>(rCandidate);
if (!tryDrawBorderLinePrimitive2DDirect(rBorder)) if (rBorder.isHorizontalOrVertical(getViewInformation2D()))
{ {
if (rBorder.getStyle() == SvxBorderLineStyle::DOUBLE) AntialiasingFlags nAntiAliasing = mpOutputDevice->GetAntialiasing();
{ mpOutputDevice->SetAntialiasing(nAntiAliasing & ~AntialiasingFlags::EnableB2dDraw);
primitive2d::Primitive2DContainer aContainer;
rBorder.createDecomposition(aContainer, getViewInformation2D(), true);
process(aContainer);
}
else
process(rCandidate);
}
mpOutputDevice->SetAntialiasing(nAntiAliasing); process(rCandidate);
mpOutputDevice->SetAntialiasing(nAntiAliasing);
}
else
{
process(rCandidate);
}
break; break;
} }
default : default :

View File

@ -64,7 +64,6 @@ namespace drawinglayer
bool tryDrawPolyPolygonColorPrimitive2DDirect(const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D& rSource, double fTransparency); bool tryDrawPolyPolygonColorPrimitive2DDirect(const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D& rSource, double fTransparency);
bool tryDrawPolygonHairlinePrimitive2DDirect(const drawinglayer::primitive2d::PolygonHairlinePrimitive2D& rSource, double fTransparency); bool tryDrawPolygonHairlinePrimitive2DDirect(const drawinglayer::primitive2d::PolygonHairlinePrimitive2D& rSource, double fTransparency);
bool tryDrawPolygonStrokePrimitive2DDirect(const drawinglayer::primitive2d::PolygonStrokePrimitive2D& rSource, double fTransparency); bool tryDrawPolygonStrokePrimitive2DDirect(const drawinglayer::primitive2d::PolygonStrokePrimitive2D& rSource, double fTransparency);
bool tryDrawBorderLinePrimitive2DDirect(const drawinglayer::primitive2d::BorderLinePrimitive2D& rSource);
public: public:
/// constructor/destructor /// constructor/destructor

View File

@ -66,27 +66,29 @@ namespace drawinglayer
bool mbHasGapColor; bool mbHasGapColor;
SvxBorderLineStyle mnStyle; SvxBorderLineStyle mnStyle;
double mfPatternScale; double mfPatternScale;
/// local helpers // for view dependent decomposition in the case with distance (gap),
double getWidth( // remember the last used concrete mfDistance, see get2DDecomposition
const geometry::ViewInformation2D& rViewInformation) const; // implementation
double mfDiscreteDistance;
/// local helpers
bool isInsideUsed() const bool isInsideUsed() const
{ {
return !basegfx::fTools::equalZero(mfLeftWidth); return !basegfx::fTools::equalZero(mfLeftWidth);
} }
bool isDistanceUsed() const
{
return !basegfx::fTools::equalZero(mfDistance);
}
bool isOutsideUsed() const bool isOutsideUsed() const
{ {
return !basegfx::fTools::equalZero(mfRightWidth); return !basegfx::fTools::equalZero(mfRightWidth);
} }
protected:
virtual basegfx::B2DPolyPolygon getClipPolygon(
const geometry::ViewInformation2D& rViewInformation) const;
/// create local decomposition /// create local decomposition
virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const override; virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation) const override;
@ -125,12 +127,16 @@ namespace drawinglayer
bool hasGapColor( ) const { return mbHasGapColor; } bool hasGapColor( ) const { return mbHasGapColor; }
SvxBorderLineStyle getStyle () const { return mnStyle; } SvxBorderLineStyle getStyle () const { return mnStyle; }
double getPatternScale() const { return mfPatternScale; } double getPatternScale() const { return mfPatternScale; }
/// Same as create2DDecomposition(), but can do pixel correction if requested.
void createDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& rViewInformation, bool bPixelCorrection) const; /// helper to decide if AntiAliasing should be used
bool isHorizontalOrVertical(const geometry::ViewInformation2D& rViewInformation) const;
/// compare operator /// compare operator
virtual bool operator==(const BasePrimitive2D& rPrimitive) const override; virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
/// Override standard getDecomposition to be view-dependent here
virtual void get2DDecomposition(Primitive2DDecompositionVisitor& rVisitor, const geometry::ViewInformation2D& rViewInformation) const override;
/// provide unique ID /// provide unique ID
DeclPrimitive2DIDBlock() DeclPrimitive2DIDBlock()
}; };

View File

@ -1,65 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_CLIPPEDBORDERLINEPRIMITIVE2D_HXX
#define INCLUDED_DRAWINGLAYER_PRIMITIVE2D_CLIPPEDBORDERLINEPRIMITIVE2D_HXX
#include <drawinglayer/drawinglayerdllapi.h>
#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
#include <basegfx/polygon/b2dpolypolygon.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
namespace drawinglayer
{
namespace primitive2d
{
/** BorderLinePrimitive2D clipped by the intersection with a provided
polygon.
*/
class DRAWINGLAYER_DLLPUBLIC ClippedBorderLinePrimitive2D : public BorderLinePrimitive2D
{
private:
const basegfx::B2DPolygon maIntersection;
protected:
virtual basegfx::B2DPolyPolygon getClipPolygon(
const geometry::ViewInformation2D& rViewInformation) const override;
public:
/// constructor
ClippedBorderLinePrimitive2D(
const basegfx::B2DPoint& rStart,
const basegfx::B2DPoint& rEnd,
double fLeftWidth,
double fDistance,
double fRightWidth,
const basegfx::B2DPolygon& rIntersection,
const basegfx::BColor& rRGBColorRight,
const basegfx::BColor& rRGBColorLeft,
const basegfx::BColor& rRGBColorGap,
bool bHasGapColor,
SvxBorderLineStyle nStyle,
double fPatternScale );
/// compare operator
virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
/// provide unique ID
DeclPrimitive2DIDBlock()
};
} // end of namespace primitive2d
} // end of namespace drawinglayer
#endif //INCLUDED_DRAWINGLAYER_PRIMITIVE2D_CLIPPEDBORDERLINEPRIMITIVE2D_HXX
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@ -429,7 +429,7 @@ SVX_DLLPUBLIC bool CheckFrameBorderConnectable(
| \ / | | \ / |
rLFromB \ / rRFromB rLFromB \ / rRFromB
*/ */
SVX_DLLPUBLIC drawinglayer::primitive2d::Primitive2DContainer CreateBorderPrimitives( SVX_DLLPUBLIC drawinglayer::primitive2d::Primitive2DReference CreateBorderPrimitives(
const Point& rLPos, /// Reference point for left end of the processed frame border. const Point& rLPos, /// Reference point for left end of the processed frame border.
const Point& rRPos, /// Reference point for right end of the processed frame border. const Point& rRPos, /// Reference point for right end of the processed frame border.
const Style& rBorder, /// Style of the processed frame border. const Style& rBorder, /// Style of the processed frame border.
@ -451,7 +451,7 @@ SVX_DLLPUBLIC drawinglayer::primitive2d::Primitive2DContainer CreateBorderPrimit
const long rRotationB = 9000 /// Angle of the bottom slanted frames in 100th of degree const long rRotationB = 9000 /// Angle of the bottom slanted frames in 100th of degree
); );
SVX_DLLPUBLIC drawinglayer::primitive2d::Primitive2DContainer CreateBorderPrimitives( SVX_DLLPUBLIC drawinglayer::primitive2d::Primitive2DReference CreateBorderPrimitives(
const Point& rLPos, /// Reference point for left end of the processed frame border. const Point& rLPos, /// Reference point for left end of the processed frame border.
const Point& rRPos, /// Reference point for right end of the processed frame border. const Point& rRPos, /// Reference point for right end of the processed frame border.
const Style& rBorder, /// Style of the processed frame border. const Style& rBorder, /// Style of the processed frame border.
@ -469,10 +469,6 @@ SVX_DLLPUBLIC drawinglayer::primitive2d::Primitive2DContainer CreateBorderPrimit
const long rRotationB = 9000 /// Angle of the bottom slanted frame in 100th of degrees const long rRotationB = 9000 /// Angle of the bottom slanted frame in 100th of degrees
); );
SVX_DLLPUBLIC drawinglayer::primitive2d::Primitive2DContainer CreateClippedBorderPrimitives (
const Point& rStart, const Point& rEnd, const Style& rBorder,
const tools::Rectangle& rClipRect );
/** Draws a horizontal frame border, regards all connected frame styles. /** Draws a horizontal frame border, regards all connected frame styles.
The frame style to draw is passed as parameter rBorder. The function The frame style to draw is passed as parameter rBorder. The function

View File

@ -331,7 +331,7 @@ public:
/** Draws the part of the specified range, that is inside the clipping range. /** Draws the part of the specified range, that is inside the clipping range.
@param pForceColor @param pForceColor
If not NULL, only this color will be used to draw all frame borders. */ If not NULL, only this color will be used to draw all frame borders. */
void DrawRange( drawinglayer::processor2d::BaseProcessor2D* rDev, void DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
size_t nFirstCol, size_t nFirstRow, size_t nFirstCol, size_t nFirstRow,
size_t nLastCol, size_t nLastRow, size_t nLastCol, size_t nLastRow,
const Color* pForceColor ) const; const Color* pForceColor ) const;
@ -344,7 +344,10 @@ public:
size_t nLastCol, size_t nLastRow ) const; size_t nLastCol, size_t nLastRow ) const;
/** Draws the part of the array, that is inside the clipping range. */ /** Draws the part of the array, that is inside the clipping range. */
void DrawArray( OutputDevice& rDev ) const; void DrawArray(OutputDevice& rDev) const;
/** Draws the part of the array, that is inside the clipping range. */
void DrawArray(drawinglayer::processor2d::BaseProcessor2D& rProcessor) const;
private: private:

View File

@ -1458,7 +1458,7 @@ void ScOutputData::DrawFrame(vcl::RenderContext& rRenderContext)
{ {
size_t nRow2 = nRow1; size_t nRow2 = nRow1;
while( (nRow2 + 1 <= nLastRow) && pRowInfo[ nRow2 + 1 ].bChanged ) ++nRow2; while( (nRow2 + 1 <= nLastRow) && pRowInfo[ nRow2 + 1 ].bChanged ) ++nRow2;
rArray.DrawRange( pProcessor.get(), nFirstCol, nRow1, nLastCol, nRow2, pForceColor ); rArray.DrawRange( *pProcessor.get(), nFirstCol, nRow1, nLastCol, nRow2, pForceColor );
nRow1 = nRow2 + 1; nRow1 = nRow2 + 1;
} }
} }
@ -1759,58 +1759,70 @@ void ScOutputData::DrawRotatedFrame(vcl::RenderContext& rRenderContext, const Co
if (aTopLine.Prim() || aTopLine.Secn()) if (aTopLine.Prim() || aTopLine.Secn())
{ {
long nUpperRotate = lcl_getRotate( mpDoc, nTab, nX, nY - 1 ); long nUpperRotate = lcl_getRotate( mpDoc, nTab, nX, nY - 1 );
pProcessor->process( svx::frame::CreateBorderPrimitives( drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
aPoints[bLayoutRTL?1:0], aPoints[bLayoutRTL?0:1], aTopLine, aSequence.append(
svx::frame::Style(), svx::frame::CreateBorderPrimitives(
svx::frame::Style(), aPoints[bLayoutRTL?1:0], aPoints[bLayoutRTL?0:1], aTopLine,
aLeftLine, svx::frame::Style(),
svx::frame::Style(), svx::frame::Style(),
svx::frame::Style(), aLeftLine,
aRightLine, svx::frame::Style(),
pForceColor, nUpperRotate, nAttrRotate ) ); svx::frame::Style(),
aRightLine,
pForceColor, nUpperRotate, nAttrRotate ) );
pProcessor->process(aSequence);
} }
if (aBottomLine.Prim() || aBottomLine.Secn()) if (aBottomLine.Prim() || aBottomLine.Secn())
{ {
long nLowerRotate = lcl_getRotate( mpDoc, nTab, nX, nY + 1 ); long nLowerRotate = lcl_getRotate( mpDoc, nTab, nX, nY + 1 );
pProcessor->process( svx::frame::CreateBorderPrimitives( drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
aPoints[bLayoutRTL?2:3], aPoints[bLayoutRTL?3:2], aBottomLine, aSequence.append(
aLeftLine, svx::frame::CreateBorderPrimitives(
svx::frame::Style(), aPoints[bLayoutRTL?2:3], aPoints[bLayoutRTL?3:2], aBottomLine,
svx::frame::Style(), aLeftLine,
aRightLine, svx::frame::Style(),
svx::frame::Style(), svx::frame::Style(),
svx::frame::Style(), aRightLine,
pForceColor, 18000 - nAttrRotate, 18000 - nLowerRotate ) ); svx::frame::Style(),
svx::frame::Style(),
pForceColor, 18000 - nAttrRotate, 18000 - nLowerRotate ) );
pProcessor->process(aSequence);
} }
// Vertical slanted lines // Vertical slanted lines
if (aLeftLine.Prim() || aLeftLine.Secn()) if (aLeftLine.Prim() || aLeftLine.Secn())
{ {
long nLeftRotate = lcl_getRotate( mpDoc, nTab, nX - 1, nY ); long nLeftRotate = lcl_getRotate( mpDoc, nTab, nX - 1, nY );
pProcessor->process( svx::frame::CreateBorderPrimitives( drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
aPoints[0], aPoints[3], aLeftLine, aSequence.append(
aTopLine, svx::frame::CreateBorderPrimitives(
svx::frame::Style(), aPoints[0], aPoints[3], aLeftLine,
svx::frame::Style(), aTopLine,
aBottomLine, svx::frame::Style(),
svx::frame::Style(), svx::frame::Style(),
svx::frame::Style(), aBottomLine,
pForceColor, nAttrRotate, nLeftRotate ) ); svx::frame::Style(),
svx::frame::Style(),
pForceColor, nAttrRotate, nLeftRotate ) );
pProcessor->process(aSequence);
} }
if (aRightLine.Prim() || aRightLine.Secn()) if (aRightLine.Prim() || aRightLine.Secn())
{ {
long nRightRotate = lcl_getRotate( mpDoc, nTab, nX + 1, nY ); long nRightRotate = lcl_getRotate( mpDoc, nTab, nX + 1, nY );
pProcessor->process( svx::frame::CreateBorderPrimitives( drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
aPoints[1], aPoints[2], aRightLine, aSequence.append(
svx::frame::Style(), svx::frame::CreateBorderPrimitives(
svx::frame::Style(), aPoints[1], aPoints[2], aRightLine,
aTopLine, svx::frame::Style(),
svx::frame::Style(), svx::frame::Style(),
svx::frame::Style(), aTopLine,
aBottomLine, svx::frame::Style(),
pForceColor, 18000 - nRightRotate, 18000 - nAttrRotate ) ); svx::frame::Style(),
aBottomLine,
pForceColor, 18000 - nRightRotate, 18000 - nAttrRotate ) );
pProcessor->process(aSequence);
} }
} }
} }

View File

@ -33,7 +33,6 @@
#include <basegfx/polygon/b2dpolygontools.hxx> #include <basegfx/polygon/b2dpolygontools.hxx>
#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx> #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
#include <drawinglayer/primitive2d/clippedborderlineprimitive2d.hxx>
using namespace ::com::sun::star; using namespace ::com::sun::star;
@ -1349,9 +1348,34 @@ bool CheckFrameBorderConnectable( const Style& rLBorder, const Style& rRBorder,
// Drawing functions // Drawing functions
// get offset to center of line in question
double lcl_getCenterOfLineOffset(const Style& rBorder, bool bLeftEdge)
{
const bool bPrimUsed(!basegfx::fTools::equalZero(rBorder.Prim())); // left
const bool bDistUsed(!basegfx::fTools::equalZero(rBorder.Dist())); // distance
const bool bSecnUsed(!basegfx::fTools::equalZero(rBorder.Secn())); // right
double lcl_GetExtent( const Style& rBorder, const Style& rSide, const Style& rOpposite, if (bDistUsed || bSecnUsed)
long nAngleSide, long nAngleOpposite ) {
// double line, get center by adding half ditance and half line width.
// bLeftEdge defines which line to use
return (rBorder.Dist() + (bLeftEdge ? rBorder.Prim() : rBorder.Secn())) * 0.5;
}
else if (bPrimUsed)
{
// single line, get center
return rBorder.Prim() * 0.5;
}
// no line width at all, stay on unit vector
return 0.0;
}
double lcl_GetExtent(
const Style& rBorder, const Style& rSide, const Style& rOpposite,
long nAngleSide, long nAngleOpposite,
bool bLeftEdge, // left or right of rBorder
bool bOtherLeft ) // left or right of rSide/rOpposite
{ {
Style aOtherBorder = rSide; Style aOtherBorder = rSide;
long nOtherAngle = nAngleSide; long nOtherAngle = nAngleSide;
@ -1370,7 +1394,8 @@ double lcl_GetExtent( const Style& rBorder, const Style& rSide, const Style& rOp
// Let's assume the border we are drawing is horizontal and compute all the angles / distances from this // Let's assume the border we are drawing is horizontal and compute all the angles / distances from this
basegfx::B2DVector aBaseVector( 1.0, 0.0 ); basegfx::B2DVector aBaseVector( 1.0, 0.0 );
basegfx::B2DPoint aBasePoint( 0.0, static_cast<double>( rBorder.GetWidth() / 2 ) ); // added support to get the distances to the centers of the line, *not* the outre edge
basegfx::B2DPoint aBasePoint(0.0, lcl_getCenterOfLineOffset(rBorder, bLeftEdge));
basegfx::B2DHomMatrix aRotation; basegfx::B2DHomMatrix aRotation;
aRotation.rotate( double( nOtherAngle ) * M_PI / 18000.0 ); aRotation.rotate( double( nOtherAngle ) * M_PI / 18000.0 );
@ -1378,7 +1403,8 @@ double lcl_GetExtent( const Style& rBorder, const Style& rSide, const Style& rOp
basegfx::B2DVector aOtherVector = aRotation * aBaseVector; basegfx::B2DVector aOtherVector = aRotation * aBaseVector;
// Compute a line shifted by half the width of the other border // Compute a line shifted by half the width of the other border
basegfx::B2DVector aPerpendicular = basegfx::getNormalizedPerpendicular( aOtherVector ); basegfx::B2DVector aPerpendicular = basegfx::getNormalizedPerpendicular( aOtherVector );
basegfx::B2DPoint aOtherPoint = basegfx::B2DPoint() + aPerpendicular * aOtherBorder.GetWidth() / 2; // added support to get the distances to the centers of the line, *not* the outre edge
basegfx::B2DPoint aOtherPoint = basegfx::B2DPoint() + aPerpendicular * lcl_getCenterOfLineOffset(aOtherBorder, bOtherLeft);
// Find the cut between the two lines // Find the cut between the two lines
double nCut = 0.0; double nCut = 0.0;
@ -1389,67 +1415,32 @@ double lcl_GetExtent( const Style& rBorder, const Style& rSide, const Style& rOp
return nCut; return nCut;
} }
basegfx::B2DPoint lcl_PointToB2DPoint( const Point& rPoint ) drawinglayer::primitive2d::Primitive2DReference CreateBorderPrimitives(
{
return basegfx::B2DPoint(rPoint.getX(), rPoint.getY());
}
drawinglayer::primitive2d::Primitive2DContainer CreateClippedBorderPrimitives (
const Point& rStart, const Point& rEnd, const Style& rBorder,
const tools::Rectangle& rClipRect )
{
drawinglayer::primitive2d::Primitive2DContainer aSequence( 1 );
basegfx::B2DPolygon aPolygon;
aPolygon.append( lcl_PointToB2DPoint( rClipRect.TopLeft( ) ) );
aPolygon.append( lcl_PointToB2DPoint( rClipRect.TopRight( ) ) );
aPolygon.append( lcl_PointToB2DPoint( rClipRect.BottomRight( ) ) );
aPolygon.append( lcl_PointToB2DPoint( rClipRect.BottomLeft( ) ) );
aPolygon.setClosed( true );
aSequence[0] = new drawinglayer::primitive2d::ClippedBorderLinePrimitive2D(
lcl_PointToB2DPoint( rStart ),
lcl_PointToB2DPoint( rEnd ),
rBorder.Prim(),
rBorder.Dist(),
rBorder.Secn(),
aPolygon,
rBorder.GetColorSecn().getBColor(),
rBorder.GetColorPrim().getBColor(),
rBorder.GetColorGap().getBColor(),
rBorder.UseGapColor(), rBorder.Type(), rBorder.PatternScale() );
return aSequence;
}
drawinglayer::primitive2d::Primitive2DContainer CreateBorderPrimitives(
const Point& rLPos, const Point& rRPos, const Style& rBorder, const Point& rLPos, const Point& rRPos, const Style& rBorder,
const DiagStyle& /*rLFromTR*/, const Style& rLFromT, const Style& /*rLFromL*/, const Style& rLFromB, const DiagStyle& /*rLFromBR*/, const DiagStyle& /*rLFromTR*/, const Style& rLFromT, const Style& /*rLFromL*/, const Style& rLFromB, const DiagStyle& /*rLFromBR*/,
const DiagStyle& /*rRFromTL*/, const Style& rRFromT, const Style& /*rRFromR*/, const Style& rRFromB, const DiagStyle& /*rRFromBL*/, const DiagStyle& /*rRFromTL*/, const Style& rRFromT, const Style& /*rRFromR*/, const Style& rRFromB, const DiagStyle& /*rRFromBL*/,
const Color* /*pForceColor*/, long nRotateT, long nRotateB ) const Color* /*pForceColor*/, long nRotateT, long nRotateB )
{ {
drawinglayer::primitive2d::Primitive2DContainer aSequence( 1 );
basegfx::B2DPoint aStart( rLPos.getX(), rLPos.getY() ); basegfx::B2DPoint aStart( rLPos.getX(), rLPos.getY() );
basegfx::B2DPoint aEnd( rRPos.getX(), rRPos.getY() ); basegfx::B2DPoint aEnd( rRPos.getX(), rRPos.getY() );
aSequence[0] = new drawinglayer::primitive2d::BorderLinePrimitive2D( return drawinglayer::primitive2d::Primitive2DReference(
aStart, aEnd, new drawinglayer::primitive2d::BorderLinePrimitive2D(
rBorder.Prim(), aStart, aEnd,
rBorder.Dist(), rBorder.Prim(),
rBorder.Secn(), rBorder.Dist(),
lcl_GetExtent( rBorder, rLFromT, rLFromB, nRotateT, - nRotateB ), rBorder.Secn(),
lcl_GetExtent( rBorder, rRFromT, rRFromB, 18000 - nRotateT, nRotateB - 18000 ), lcl_GetExtent( rBorder, rLFromT, rLFromB, nRotateT, - nRotateB, true, false ), // top-left, so left for rBorder and right for left outer
lcl_GetExtent( rBorder, rLFromB, rLFromT, nRotateB, - nRotateT ), lcl_GetExtent( rBorder, rRFromT, rRFromB, 18000 - nRotateT, nRotateB - 18000, true, true ), // top-right
lcl_GetExtent( rBorder, rRFromB, rRFromT, 18000 - nRotateB, nRotateT - 18000 ), lcl_GetExtent( rBorder, rLFromB, rLFromT, nRotateB, - nRotateT, false, false ), // bottom-left
rBorder.GetColorSecn().getBColor(), lcl_GetExtent( rBorder, rRFromB, rRFromT, 18000 - nRotateB, nRotateT - 18000, false, true ), // bottom-right
rBorder.GetColorPrim().getBColor(), rBorder.GetColorSecn().getBColor(),
rBorder.GetColorGap().getBColor(), rBorder.GetColorPrim().getBColor(),
rBorder.UseGapColor(), rBorder.Type(), rBorder.PatternScale() ); rBorder.GetColorGap().getBColor(),
rBorder.UseGapColor(), rBorder.Type(), rBorder.PatternScale()));
return aSequence;
} }
drawinglayer::primitive2d::Primitive2DContainer CreateBorderPrimitives( drawinglayer::primitive2d::Primitive2DReference CreateBorderPrimitives(
const Point& rLPos, const Point& rRPos, const Style& rBorder, const Point& rLPos, const Point& rRPos, const Style& rBorder,
const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB,
const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, const Style& rRFromT, const Style& rRFromR, const Style& rRFromB,

View File

@ -23,6 +23,7 @@
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include <vcl/outdev.hxx> #include <vcl/outdev.hxx>
#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
namespace svx { namespace svx {
namespace frame { namespace frame {
@ -878,7 +879,7 @@ void Array::MirrorSelfX()
} }
// drawing // drawing
void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D* pProcessor, void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow, size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow,
const Color* pForceColor ) const const Color* pForceColor ) const
{ {
@ -907,23 +908,52 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D* pProcessor,
size_t _nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow ); size_t _nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
const Style aTlbrStyle = GetCellStyleTLBR( _nFirstCol, _nFirstRow ); const Style aTlbrStyle = GetCellStyleTLBR( _nFirstCol, _nFirstRow );
if ( aTlbrStyle.GetWidth( ) ) if (aTlbrStyle.GetWidth())
pProcessor->process( CreateClippedBorderPrimitives( {
aRect.TopLeft(), aRect.BottomRight(), drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
aTlbrStyle, aRect ) ); aSequence.append(
new drawinglayer::primitive2d::BorderLinePrimitive2D(
basegfx::B2DPoint(aRect.Left(), aRect.Top()),
basegfx::B2DPoint(aRect.Right(), aRect.Bottom()),
aTlbrStyle.Prim(),
aTlbrStyle.Dist(),
aTlbrStyle.Secn(),
0.0, 0.0, 0.0, 0.0,
aTlbrStyle.GetColorSecn().getBColor(),
aTlbrStyle.GetColorPrim().getBColor(),
aTlbrStyle.GetColorGap().getBColor(),
aTlbrStyle.UseGapColor(),
aTlbrStyle.Type(),
aTlbrStyle.PatternScale()));
rProcessor.process(aSequence);
}
const Style aBltrStyle = GetCellStyleBLTR( _nFirstCol, _nFirstRow ); const Style aBltrStyle = GetCellStyleBLTR( _nFirstCol, _nFirstRow );
if ( aBltrStyle.GetWidth( ) ) if (aBltrStyle.GetWidth())
pProcessor->process( CreateClippedBorderPrimitives( {
aRect.BottomLeft(), aRect.TopRight(), drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
aBltrStyle, aRect ) ); aSequence.append(
new drawinglayer::primitive2d::BorderLinePrimitive2D(
basegfx::B2DPoint(aRect.Left(), aRect.Bottom()),
basegfx::B2DPoint(aRect.Right(), aRect.Top()),
aBltrStyle.Prim(),
aBltrStyle.Dist(),
aBltrStyle.Secn(),
0.0, 0.0, 0.0, 0.0,
aBltrStyle.GetColorSecn().getBColor(),
aBltrStyle.GetColorPrim().getBColor(),
aBltrStyle.GetColorGap().getBColor(),
aBltrStyle.UseGapColor(),
aBltrStyle.Type(),
aBltrStyle.PatternScale()));
rProcessor.process(aSequence);
}
} }
} }
} }
} }
// *** horizontal frame borders *** // *** horizontal frame borders ***
for( nRow = nFirstRow; nRow <= nLastRow + 1; ++nRow ) for( nRow = nFirstRow; nRow <= nLastRow + 1; ++nRow )
{ {
double fAngle = mxImpl->GetHorDiagAngle( nFirstCol, nRow ); double fAngle = mxImpl->GetHorDiagAngle( nFirstCol, nRow );
@ -970,10 +1000,27 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D* pProcessor,
{ {
// draw previous frame border // draw previous frame border
Point aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.Y() ); Point aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.Y() );
if( pStart->Prim() && (aStartPos.X() <= aEndPos.X()) ) if (pStart->Prim() && (aStartPos.X() <= aEndPos.X()))
pProcessor->process( CreateBorderPrimitives( aStartPos, aEndPos, *pStart, {
aStartLFromTR, *pStartLFromT, *pStartLFromL, *pStartLFromB, aStartLFromBR, drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
aEndRFromTL, *pEndRFromT, *pEndRFromR, *pEndRFromB, aEndRFromBL, pForceColor ) ); aSequence.append(
CreateBorderPrimitives(
aStartPos,
aEndPos,
*pStart,
aStartLFromTR,
*pStartLFromT,
*pStartLFromL,
*pStartLFromB,
aStartLFromBR,
aEndRFromTL,
*pEndRFromT,
*pEndRFromR,
*pEndRFromB,
aEndRFromBL,
pForceColor));
rProcessor.process(aSequence);
}
// re-init "*Start***" variables // re-init "*Start***" variables
aStartPos = aEndPos; aStartPos = aEndPos;
@ -995,10 +1042,27 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D* pProcessor,
// draw last frame border // draw last frame border
Point aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.Y() ); Point aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.Y() );
if( pStart->Prim() && (aStartPos.X() <= aEndPos.X()) ) if (pStart->Prim() && (aStartPos.X() <= aEndPos.X()))
pProcessor->process( CreateBorderPrimitives( aStartPos, aEndPos, *pStart, {
aStartLFromTR, *pStartLFromT, *pStartLFromL, *pStartLFromB, aStartLFromBR, drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
aEndRFromTL, *pEndRFromT, *pEndRFromR, *pEndRFromB, aEndRFromBL, pForceColor ) ); aSequence.append(
CreateBorderPrimitives(
aStartPos,
aEndPos,
*pStart,
aStartLFromTR,
*pStartLFromT,
*pStartLFromL,
*pStartLFromB,
aStartLFromBR,
aEndRFromTL,
*pEndRFromT,
*pEndRFromR,
*pEndRFromB,
aEndRFromBL,
pForceColor));
rProcessor.process(aSequence);
}
} }
// *** vertical frame borders *** // *** vertical frame borders ***
@ -1048,10 +1112,35 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D* pProcessor,
{ {
// draw previous frame border // draw previous frame border
Point aEndPos( aStartPos.X(), mxImpl->GetRowPosition( nRow ) ); Point aEndPos( aStartPos.X(), mxImpl->GetRowPosition( nRow ) );
if( pStart->Prim() && (aStartPos.Y() <= aEndPos.Y()) ) if (pStart->Prim() && (aStartPos.Y() <= aEndPos.Y()))
pProcessor->process( CreateBorderPrimitives( aEndPos, aStartPos, *pStart, {
aEndBFromTL, *pEndBFromL, *pEndBFromB, *pEndBFromR, aEndBFromTR, drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
aStartTFromBL, *pStartTFromL, *pStartTFromT, *pStartTFromR, aStartTFromBR, pForceColor ) ); aSequence.append(
CreateBorderPrimitives(
// This replaces DrawVerFrameBorder which went from top to bottom. To be able to use
// the same method as for horizontal (CreateBorderPrimitives), the given borders
// have to be rearranged. Best is to look at the explanations of parameters in
// framelink.hxx and the former calls to DrawVerFrameBorder and it's parameters.
// In principle, the order of the five TFrom and BFrom has to be
// inverted to get the same orientation. Before, EndPos and StartPos were changed
// which avoids the reordering, but also leads to inverted line patters for vertical
// lines
aStartPos,
aEndPos,
*pStart,
aStartTFromBR,
*pStartTFromR,
*pStartTFromT,
*pStartTFromL,
aStartTFromBL,
aEndBFromTR,
*pEndBFromR,
*pEndBFromB,
*pEndBFromL,
aEndBFromTL,
pForceColor));
rProcessor.process(aSequence);
}
// re-init "*Start***" variables // re-init "*Start***" variables
aStartPos = aEndPos; aStartPos = aEndPos;
@ -1073,10 +1162,28 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D* pProcessor,
// draw last frame border // draw last frame border
Point aEndPos( aStartPos.X(), mxImpl->GetRowPosition( nRow ) ); Point aEndPos( aStartPos.X(), mxImpl->GetRowPosition( nRow ) );
if( pStart->Prim() && (aStartPos.Y() <= aEndPos.Y()) ) if (pStart->Prim() && (aStartPos.Y() <= aEndPos.Y()))
pProcessor->process( CreateBorderPrimitives( aEndPos, aStartPos, *pStart, {
aEndBFromTL, *pEndBFromL, *pEndBFromB, *pEndBFromR, aEndBFromTR, drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
aStartTFromBL, *pStartTFromL, *pStartTFromT, *pStartTFromR, aStartTFromBR, pForceColor ) ); aSequence.append(
CreateBorderPrimitives(
// also reordered, see call to CreateBorderPrimitives above
aStartPos,
aEndPos,
*pStart,
aStartTFromBR,
*pStartTFromR,
*pStartTFromT,
*pStartTFromL,
aStartTFromBL,
aEndBFromTR,
*pEndBFromR,
*pEndBFromB,
*pEndBFromL,
aEndBFromTL,
pForceColor));
rProcessor.process(aSequence);
}
} }
} }
@ -1291,6 +1398,12 @@ void Array::DrawArray( OutputDevice& rDev ) const
DrawRange( rDev, 0, 0, mxImpl->mnWidth - 1, mxImpl->mnHeight - 1 ); DrawRange( rDev, 0, 0, mxImpl->mnWidth - 1, mxImpl->mnHeight - 1 );
} }
void Array::DrawArray(drawinglayer::processor2d::BaseProcessor2D& rProcessor) const
{
if (mxImpl->mnWidth && mxImpl->mnHeight)
DrawRange(rProcessor, 0, 0, mxImpl->mnWidth - 1, mxImpl->mnHeight - 1, nullptr);
}
#undef ORIGCELL #undef ORIGCELL
#undef CELLACC #undef CELLACC

View File

@ -28,6 +28,7 @@
#include <com/sun/star/accessibility/AccessibleEventId.hpp> #include <com/sun/star/accessibility/AccessibleEventId.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp> #include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <vcl/settings.hxx> #include <vcl/settings.hxx>
#include <drawinglayer/processor2d/processor2dtools.hxx>
#include <svx/dialogs.hrc> #include <svx/dialogs.hrc>
#include "bitmaps.hlst" #include "bitmaps.hlst"
@ -671,7 +672,36 @@ void FrameSelectorImpl::DrawAllFrameBorders()
maArray.SetCellStyleDiag( nCol, nRow, maTLBR.GetUIStyle(), maBLTR.GetUIStyle() ); maArray.SetCellStyleDiag( nCol, nRow, maTLBR.GetUIStyle(), maBLTR.GetUIStyle() );
// Let the helper array draw itself // Let the helper array draw itself
maArray.DrawArray( *mpVirDev.get() ); static bool bUsePrimitives(true);
if (bUsePrimitives)
{
// This is used in the dialog/control for 'Border' attributes. When using
// the original paint below instead of primitives, the advantage currently
// is the correct visualization of diagonal line(s) including overlaying,
// but the rest is bad. Since the edit views use primitives and the preview
// should be 'real' I opt for also changing this to primitives. I will
// keep the old solution and add a switch (above) based on a static bool so
// that interested people may test this out in the debugger.
// This is one more hint to enhance the primitive visualization further to
// support diagonals better - that's the way to go.
const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D;
std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(
drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice(
*mpVirDev.get(),
aNewViewInformation2D));
if (pProcessor2D)
{
maArray.DrawArray(*pProcessor2D.get());
pProcessor2D.reset();
}
}
else
{
// original paint
maArray.DrawArray(*mpVirDev.get());
}
} }
void FrameSelectorImpl::DrawVirtualDevice() void FrameSelectorImpl::DrawVirtualDevice()

View File

@ -2747,33 +2747,37 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
if (bHori) if (bHori)
{ {
mrTabFrame.ProcessPrimitives( svx::frame::CreateBorderPrimitives( drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
aPaintStart, aSequence.append(
aPaintEnd, svx::frame::CreateBorderPrimitives(
aStyles[ 0 ], // current style aPaintStart,
aStyles[ 1 ], // aLFromT aPaintEnd,
aStyles[ 2 ], // aLFromL aStyles[ 0 ], // current style
aStyles[ 3 ], // aLFromB aStyles[ 1 ], // aLFromT
aStyles[ 4 ], // aRFromT aStyles[ 2 ], // aLFromL
aStyles[ 5 ], // aRFromR aStyles[ 3 ], // aLFromB
aStyles[ 6 ], // aRFromB aStyles[ 4 ], // aRFromT
pTmpColor) aStyles[ 5 ], // aRFromR
); aStyles[ 6 ], // aRFromB
pTmpColor));
mrTabFrame.ProcessPrimitives(aSequence);
} }
else else
{ {
mrTabFrame.ProcessPrimitives( svx::frame::CreateBorderPrimitives( drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
aPaintEnd, aSequence.append(
aPaintStart, svx::frame::CreateBorderPrimitives(
aStyles[ 0 ], // current style aPaintEnd,
aStyles[ 4 ], // aBFromL aPaintStart,
aStyles[ 5 ], // aBFromB aStyles[ 0 ], // current style
aStyles[ 6 ], // aBFromR aStyles[ 4 ], // aBFromL
aStyles[ 1 ], // aTFromL aStyles[ 5 ], // aBFromB
aStyles[ 2 ], // aTFromT aStyles[ 6 ], // aBFromR
aStyles[ 3 ], // aTFromR aStyles[ 1 ], // aTFromL
pTmpColor) aStyles[ 2 ], // aTFromT
); aStyles[ 3 ], // aTFromR
pTmpColor));
mrTabFrame.ProcessPrimitives(aSequence);
} }
} }