1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <basegfx/color/bcolor.hxx>
21 #include <basegfx/color/bcolortools.hxx>
23 #include <editeng/borderline.hxx>
24 #include <editeng/itemtype.hxx>
27 using namespace ::com::sun::star::table::BorderLineStyle
;
29 // class SvxBorderLine --------------------------------------------------
33 Color
lcl_compute3DColor( Color aMain
, int nLight
, int nMedium
, int nDark
)
35 basegfx::BColor color
= aMain
.getBColor( );
36 basegfx::BColor hsl
= basegfx::tools::rgb2hsl( color
);
39 if ( hsl
.getZ( ) >= 0.5 )
41 else if ( 0.5 > hsl
.getZ() && hsl
.getZ() >= 0.25 )
46 double L
= hsl
.getZ() * 255.0 + nCoef
;
47 hsl
.setZ( L
/ 255.0 );
48 color
= basegfx::tools::hsl2rgb( hsl
);
50 return Color( color
);
52 } // Anonymous namespace
56 Color
SvxBorderLine::darkColor( Color aMain
)
61 Color
SvxBorderLine::lightColor( Color aMain
)
64 // Divide Luminance by 2
65 basegfx::BColor color
= aMain
.getBColor( );
66 basegfx::BColor hsl
= basegfx::tools::rgb2hsl( color
);
67 hsl
.setZ( hsl
.getZ() * 0.5 );
68 color
= basegfx::tools::hsl2rgb( hsl
);
70 return Color( color
);
74 Color
SvxBorderLine::threeDLightColor( Color aMain
)
76 // These values have been defined in an empirical way
77 return lcl_compute3DColor( aMain
, 3, 40, 83 );
80 Color
SvxBorderLine::threeDDarkColor( Color aMain
)
82 // These values have been defined in an empirical way
83 return lcl_compute3DColor( aMain
, -85, -43, -1 );
86 Color
SvxBorderLine::threeDMediumColor( Color aMain
)
88 // These values have been defined in an empirical way
89 return lcl_compute3DColor( aMain
, -42, -0, 42 );
92 SvxBorderLine::SvxBorderLine( const Color
*pCol
, long nWidth
,
93 SvxBorderStyle nStyle
, bool bUseLeftTop
,
94 Color (*pColorOutFn
)( Color
), Color (*pColorInFn
)( Color
),
95 Color (*pColorGapFn
)( Color
) )
97 , m_bMirrorWidths( false )
98 , m_aWidthImpl( SvxBorderLine::getWidthImpl( nStyle
) )
102 , m_bUseLeftTop( bUseLeftTop
)
103 , m_pColorOutFn( pColorOutFn
)
104 , m_pColorInFn( pColorInFn
)
105 , m_pColorGapFn( pColorGapFn
)
113 ConvertBorderStyleFromWord(int const nWordLineStyle
)
115 switch (nWordLineStyle
)
117 // First the single lines
119 case 2: // thick line
121 // and the unsupported special cases which we map to a single line
134 // then the shading beams which we represent by a double line
137 // then the double lines, for which we have good matches
139 case 10: // Don't have triple so use double
140 case 21: // Don't have double wave: use double instead
143 return THINTHICK_SMALLGAP
;
145 case 13: // Don't have thin thick thin, so use thick thin
146 return THICKTHIN_SMALLGAP
;
148 return THINTHICK_MEDIUMGAP
;
150 case 16: // Don't have thin thick thin, so use thick thin
151 return THICKTHIN_MEDIUMGAP
;
153 return THINTHICK_LARGEGAP
;
155 case 19: // Don't have thin thick thin, so use thick thin
156 return THICKTHIN_LARGEGAP
;
166 return css::table::BorderLineStyle::NONE
;
170 static const double THINTHICK_SMALLGAP_line2
= 15.0;
171 static const double THINTHICK_SMALLGAP_gap
= 15.0;
172 static const double THINTHICK_LARGEGAP_line1
= 30.0;
173 static const double THINTHICK_LARGEGAP_line2
= 15.0;
174 static const double THICKTHIN_SMALLGAP_line1
= 15.0;
175 static const double THICKTHIN_SMALLGAP_gap
= 15.0;
176 static const double THICKTHIN_LARGEGAP_line1
= 15.0;
177 static const double THICKTHIN_LARGEGAP_line2
= 30.0;
178 static const double OUTSET_line1
= 15.0;
179 static const double INSET_line2
= 15.0;
182 ConvertBorderWidthFromWord(SvxBorderStyle
const eStyle
, double const i_fWidth
,
183 int const nWordLineStyle
)
185 // fdo#68779: at least for RTF, 0.75pt is the default if width is missing
186 double const fWidth((i_fWidth
== 0.0) ? 15.0 : i_fWidth
);
191 switch (nWordLineStyle
)
194 return (fWidth
* 2.0); // thick
195 case 5: // fdo#55526: map 0 hairline width to > 0
196 return (fWidth
> 1.0) ? fWidth
: 1.0;
208 // Display a minimum effective border width of 1pt
210 return (fWidth
> 0 && fWidth
< 20) ? 20 : fWidth
;
216 case THINTHICK_MEDIUMGAP
:
217 case THICKTHIN_MEDIUMGAP
:
222 case THINTHICK_SMALLGAP
:
223 return fWidth
+ THINTHICK_SMALLGAP_line2
+ THINTHICK_SMALLGAP_gap
;
225 case THINTHICK_LARGEGAP
:
226 return fWidth
+ THINTHICK_LARGEGAP_line1
+ THINTHICK_LARGEGAP_line2
;
228 case THICKTHIN_SMALLGAP
:
229 return fWidth
+ THICKTHIN_SMALLGAP_line1
+ THICKTHIN_SMALLGAP_gap
;
231 case THICKTHIN_LARGEGAP
:
232 return fWidth
+ THICKTHIN_LARGEGAP_line1
+ THICKTHIN_LARGEGAP_line2
;
235 return (fWidth
* 2.0) + OUTSET_line1
;
238 return (fWidth
* 2.0) + INSET_line2
;
241 assert(false); // should only be called for known border style
247 ConvertBorderWidthToWord(SvxBorderStyle
const eStyle
, double const fWidth
)
265 case THINTHICK_MEDIUMGAP
:
266 case THICKTHIN_MEDIUMGAP
:
271 case THINTHICK_SMALLGAP
:
272 return fWidth
- THINTHICK_SMALLGAP_line2
- THINTHICK_SMALLGAP_gap
;
274 case THINTHICK_LARGEGAP
:
275 return fWidth
- THINTHICK_LARGEGAP_line1
- THINTHICK_LARGEGAP_line2
;
277 case THICKTHIN_SMALLGAP
:
278 return fWidth
- THICKTHIN_SMALLGAP_line1
- THICKTHIN_SMALLGAP_gap
;
280 case THICKTHIN_LARGEGAP
:
281 return fWidth
- THICKTHIN_LARGEGAP_line1
- THICKTHIN_LARGEGAP_line2
;
284 return (fWidth
- OUTSET_line1
) / 2.0;
287 return (fWidth
- INSET_line2
) / 2.0;
289 case css::table::BorderLineStyle::NONE
:
293 assert(false); // should only be called for known border style
298 /** Get the BorderWithImpl object corresponding to the given #nStyle, all the
299 units handled by the resulting object are Twips and the
300 BorderWidthImpl::GetLine1() corresponds to the Outer Line.
302 BorderWidthImpl
SvxBorderLine::getWidthImpl( SvxBorderStyle nStyle
)
304 BorderWidthImpl aImpl
;
309 case css::table::BorderLineStyle::NONE
:
310 aImpl
= BorderWidthImpl( BorderWidthImplFlags::FIXED
, 0.0 );
320 aImpl
= BorderWidthImpl( BorderWidthImplFlags::CHANGE_LINE1
, 1.0 );
326 aImpl
= BorderWidthImpl(
327 BorderWidthImplFlags::CHANGE_LINE1
| BorderWidthImplFlags::CHANGE_LINE2
| BorderWidthImplFlags::CHANGE_DIST
,
328 // fdo#46112 fdo#38542 fdo#43249:
329 // non-constant witdths must sum to 1
330 1.0/3.0, 1.0/3.0, 1.0/3.0 );
334 aImpl
= BorderWidthImpl(BorderWidthImplFlags::CHANGE_DIST
, 10.0, 10.0, 1.0);
337 case THINTHICK_SMALLGAP
:
338 aImpl
= BorderWidthImpl( BorderWidthImplFlags::CHANGE_LINE1
, 1.0,
339 THINTHICK_SMALLGAP_line2
, THINTHICK_SMALLGAP_gap
);
342 case THINTHICK_MEDIUMGAP
:
343 aImpl
= BorderWidthImpl(
344 BorderWidthImplFlags::CHANGE_LINE1
| BorderWidthImplFlags::CHANGE_LINE2
| BorderWidthImplFlags::CHANGE_DIST
,
348 case THINTHICK_LARGEGAP
:
349 aImpl
= BorderWidthImpl( BorderWidthImplFlags::CHANGE_DIST
,
350 THINTHICK_LARGEGAP_line1
, THINTHICK_LARGEGAP_line2
, 1.0 );
353 case THICKTHIN_SMALLGAP
:
354 aImpl
= BorderWidthImpl( BorderWidthImplFlags::CHANGE_LINE2
, THICKTHIN_SMALLGAP_line1
,
355 1.0, THICKTHIN_SMALLGAP_gap
);
358 case THICKTHIN_MEDIUMGAP
:
359 aImpl
= BorderWidthImpl(
360 BorderWidthImplFlags::CHANGE_LINE1
| BorderWidthImplFlags::CHANGE_LINE2
| BorderWidthImplFlags::CHANGE_DIST
,
364 case THICKTHIN_LARGEGAP
:
365 aImpl
= BorderWidthImpl( BorderWidthImplFlags::CHANGE_DIST
, THICKTHIN_LARGEGAP_line1
,
366 THICKTHIN_LARGEGAP_line2
, 1.0 );
369 // Engraved / Embossed
371 * Word compat: the lines widths are exactly following this rule, shouldbe:
372 * 0.75pt up to 3pt and then 3pt
377 aImpl
= BorderWidthImpl(
378 BorderWidthImplFlags::CHANGE_LINE1
| BorderWidthImplFlags::CHANGE_LINE2
| BorderWidthImplFlags::CHANGE_DIST
,
384 * Word compat: the gap width should be measured relatively to the biggest width for the
388 aImpl
= BorderWidthImpl(
389 BorderWidthImplFlags::CHANGE_LINE2
| BorderWidthImplFlags::CHANGE_DIST
,
390 OUTSET_line1
, 0.5, 0.5 );
394 aImpl
= BorderWidthImpl(
395 BorderWidthImplFlags::CHANGE_LINE1
| BorderWidthImplFlags::CHANGE_DIST
,
396 0.5, INSET_line2
, 0.5 );
405 SvxBorderLine::SvxBorderLine( const SvxBorderLine
& r
)
412 SvxBorderLine
& SvxBorderLine::operator=( const SvxBorderLine
& r
)
415 m_nWidth
= r
.m_nWidth
;
416 m_aWidthImpl
= r
.m_aWidthImpl
;
417 m_bMirrorWidths
= r
.m_bMirrorWidths
;
420 m_nStyle
= r
.m_nStyle
;
421 m_bUseLeftTop
= r
.m_bUseLeftTop
;
422 m_pColorOutFn
= r
.m_pColorOutFn
;
423 m_pColorInFn
= r
.m_pColorInFn
;
424 m_pColorGapFn
= r
.m_pColorGapFn
;
430 void SvxBorderLine::ScaleMetrics( long nMult
, long nDiv
)
436 void SvxBorderLine::GuessLinesWidths( SvxBorderStyle nStyle
, sal_uInt16 nOut
, sal_uInt16 nIn
, sal_uInt16 nDist
)
438 if (css::table::BorderLineStyle::NONE
== nStyle
)
441 if ( nOut
> 0 && nIn
> 0 )
445 if ( nStyle
== DOUBLE
)
447 static const SvxBorderStyle aDoubleStyles
[] =
459 static size_t const len
= SAL_N_ELEMENTS(aDoubleStyles
);
461 SvxBorderStyle
nTestStyle(css::table::BorderLineStyle::NONE
);
462 for (size_t i
= 0; i
< len
&& nWidth
== 0; ++i
)
464 nTestStyle
= aDoubleStyles
[i
];
465 BorderWidthImpl aWidthImpl
= getWidthImpl( nTestStyle
);
466 nWidth
= aWidthImpl
.GuessWidth( nOut
, nIn
, nDist
);
469 // If anything matched, then set it
473 SetBorderLineStyle(nStyle
);
478 // fdo#38542: not a known double, default to something custom...
479 SetBorderLineStyle(nStyle
);
480 m_nWidth
= nOut
+ nIn
+ nDist
;
481 if (nOut
+ nIn
+ nDist
)
483 m_aWidthImpl
= BorderWidthImpl(
484 BorderWidthImplFlags::CHANGE_LINE1
| BorderWidthImplFlags::CHANGE_LINE2
| BorderWidthImplFlags::CHANGE_DIST
,
485 static_cast<double>(nOut
) / static_cast<double>(m_nWidth
),
486 static_cast<double>(nIn
) / static_cast<double>(m_nWidth
),
487 static_cast<double>(nDist
) / static_cast<double>(m_nWidth
));
493 SetBorderLineStyle(nStyle
);
494 if (nOut
== 0 && nIn
> 0)
496 // If only inner width is given swap inner and outer widths for
497 // single line styles, otherwise GuessWidth() marks this as invalid
498 // and returns a 0 width.
507 ::std::swap( nOut
, nIn
);
513 m_nWidth
= m_aWidthImpl
.GuessWidth( nOut
, nIn
, nDist
);
517 sal_uInt16
SvxBorderLine::GetOutWidth() const
519 sal_uInt16 nOut
= (sal_uInt16
)Scale( m_aWidthImpl
.GetLine1( m_nWidth
), m_nMult
, m_nDiv
);
520 if ( m_bMirrorWidths
)
521 nOut
= (sal_uInt16
)Scale( m_aWidthImpl
.GetLine2( m_nWidth
), m_nMult
, m_nDiv
);
525 sal_uInt16
SvxBorderLine::GetInWidth() const
527 sal_uInt16 nIn
= (sal_uInt16
)Scale( m_aWidthImpl
.GetLine2( m_nWidth
), m_nMult
, m_nDiv
);
528 if ( m_bMirrorWidths
)
529 nIn
= (sal_uInt16
)Scale( m_aWidthImpl
.GetLine1( m_nWidth
), m_nMult
, m_nDiv
);
533 sal_uInt16
SvxBorderLine::GetDistance() const
535 return (sal_uInt16
)Scale( m_aWidthImpl
.GetGap( m_nWidth
), m_nMult
, m_nDiv
);
540 bool SvxBorderLine::operator==( const SvxBorderLine
& rCmp
) const
542 return ( ( aColor
== rCmp
.aColor
) &&
543 ( m_nWidth
== rCmp
.m_nWidth
) &&
544 ( m_bMirrorWidths
== rCmp
.m_bMirrorWidths
) &&
545 ( m_aWidthImpl
== rCmp
.m_aWidthImpl
) &&
546 ( m_nStyle
== rCmp
.GetBorderLineStyle()) &&
547 ( m_bUseLeftTop
== rCmp
.m_bUseLeftTop
) &&
548 ( m_pColorOutFn
== rCmp
.m_pColorOutFn
) &&
549 ( m_pColorInFn
== rCmp
.m_pColorInFn
) &&
550 ( m_pColorGapFn
== rCmp
.m_pColorGapFn
) );
553 void SvxBorderLine::SetBorderLineStyle( SvxBorderStyle nNew
)
556 m_aWidthImpl
= getWidthImpl( m_nStyle
);
561 m_pColorOutFn
= threeDLightColor
;
562 m_pColorInFn
= threeDDarkColor
;
563 m_pColorGapFn
= threeDMediumColor
;
564 m_bUseLeftTop
= true;
567 m_pColorOutFn
= threeDDarkColor
;
568 m_pColorInFn
= threeDLightColor
;
569 m_pColorGapFn
= threeDMediumColor
;
570 m_bUseLeftTop
= true;
573 m_pColorOutFn
= lightColor
;
574 m_pColorInFn
= darkColor
;
575 m_bUseLeftTop
= true;
576 m_pColorGapFn
= NULL
;
579 m_pColorOutFn
= darkColor
;
580 m_pColorInFn
= lightColor
;
581 m_bUseLeftTop
= true;
582 m_pColorGapFn
= NULL
;
585 m_pColorOutFn
= darkColor
;
586 m_pColorInFn
= darkColor
;
587 m_bUseLeftTop
= false;
588 m_pColorGapFn
= NULL
;
593 Color
SvxBorderLine::GetColorOut( bool bLeftOrTop
) const
595 Color aResult
= aColor
;
597 if ( m_aWidthImpl
.IsDouble() && m_pColorOutFn
!= NULL
)
599 if ( !bLeftOrTop
&& m_bUseLeftTop
)
600 aResult
= (*m_pColorInFn
)( aColor
);
602 aResult
= (*m_pColorOutFn
)( aColor
);
608 Color
SvxBorderLine::GetColorIn( bool bLeftOrTop
) const
610 Color aResult
= aColor
;
612 if ( m_aWidthImpl
.IsDouble() && m_pColorInFn
!= NULL
)
614 if ( !bLeftOrTop
&& m_bUseLeftTop
)
615 aResult
= (*m_pColorOutFn
)( aColor
);
617 aResult
= (*m_pColorInFn
)( aColor
);
623 Color
SvxBorderLine::GetColorGap( ) const
625 Color aResult
= aColor
;
627 if ( m_aWidthImpl
.IsDouble() && m_pColorGapFn
!= NULL
)
629 aResult
= (*m_pColorGapFn
)( aColor
);
635 void SvxBorderLine::SetWidth( long nWidth
)
640 OUString
SvxBorderLine::GetValueString( SfxMapUnit eSrcUnit
,
641 SfxMapUnit eDestUnit
,
642 const IntlWrapper
* pIntl
,
643 bool bMetricStr
) const
645 static const sal_uInt16 aStyleIds
[] =
651 RID_THINTHICK_SMALLGAP
,
652 RID_THINTHICK_MEDIUMGAP
,
653 RID_THINTHICK_LARGEGAP
,
654 RID_THICKTHIN_SMALLGAP
,
655 RID_THICKTHIN_MEDIUMGAP
,
656 RID_THICKTHIN_LARGEGAP
,
666 OUString aStr
= "(" + ::GetColorString( aColor
) + OUString(cpDelim
);
668 if ( m_nStyle
< int(SAL_N_ELEMENTS(aStyleIds
)) )
670 sal_uInt16 nResId
= aStyleIds
[m_nStyle
];
671 aStr
+= EE_RESSTR(nResId
);
675 OUString sMetric
= EE_RESSTR(GetMetricId( eDestUnit
));
676 aStr
+= GetMetricText( (long)GetInWidth(), eSrcUnit
, eDestUnit
, pIntl
);
680 aStr
+= GetMetricText( (long)GetOutWidth(), eSrcUnit
, eDestUnit
, pIntl
);
684 aStr
+= GetMetricText( (long)GetDistance(), eSrcUnit
, eDestUnit
, pIntl
);
692 bool SvxBorderLine::HasPriority( const SvxBorderLine
& rOtherLine
) const
694 const sal_uInt16 nThisSize
= GetScaledWidth();
695 const sal_uInt16 nOtherSize
= rOtherLine
.GetScaledWidth();
697 if ( nThisSize
> nOtherSize
)
701 else if ( nThisSize
< nOtherSize
)
705 else if ( rOtherLine
.GetInWidth() && !GetInWidth() )
713 bool operator!=( const SvxBorderLine
& rLeft
, const SvxBorderLine
& rRight
)
715 return !(rLeft
== rRight
);
718 } // namespace editeng
720 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */