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
132 // then the shading beams which we represent by a double line
135 // then the double lines, for which we have good matches
137 case 10: // Don't have triple so use double
138 case 21: // Don't have double wave: use double instead
141 return THINTHICK_SMALLGAP
;
143 case 13: // Don't have thin thick thin, so use thick thin
144 return THICKTHIN_SMALLGAP
;
146 return THINTHICK_MEDIUMGAP
;
148 case 16: // Don't have thin thick thin, so use thick thin
149 return THICKTHIN_MEDIUMGAP
;
151 return THINTHICK_LARGEGAP
;
153 case 19: // Don't have thin thick thin, so use thick thin
154 return THICKTHIN_LARGEGAP
;
168 static const double THINTHICK_SMALLGAP_line2
= 15.0;
169 static const double THINTHICK_SMALLGAP_gap
= 15.0;
170 static const double THINTHICK_LARGEGAP_line1
= 30.0;
171 static const double THINTHICK_LARGEGAP_line2
= 15.0;
172 static const double THICKTHIN_SMALLGAP_line1
= 15.0;
173 static const double THICKTHIN_SMALLGAP_gap
= 15.0;
174 static const double THICKTHIN_LARGEGAP_line1
= 15.0;
175 static const double THICKTHIN_LARGEGAP_line2
= 30.0;
176 static const double OUTSET_line1
= 15.0;
177 static const double INSET_line2
= 15.0;
180 ConvertBorderWidthFromWord(SvxBorderStyle
const eStyle
, double const i_fWidth
,
181 int const nWordLineStyle
)
183 // fdo#68779: at least for RTF, 0.75pt is the default if width is missing
184 double const fWidth((i_fWidth
== 0.0) ? 15.0 : i_fWidth
);
189 switch (nWordLineStyle
)
192 return (fWidth
* 2.0); // thick
193 case 5: // fdo#55526: map 0 hairline width to > 0
194 return (fWidth
> 1.0) ? fWidth
: 1.0;
204 // Display a minimum effective border width of 1pt
206 return (fWidth
> 0 && fWidth
< 20) ? 20 : fWidth
;
212 case THINTHICK_MEDIUMGAP
:
213 case THICKTHIN_MEDIUMGAP
:
218 case THINTHICK_SMALLGAP
:
219 return fWidth
+ THINTHICK_SMALLGAP_line2
+ THINTHICK_SMALLGAP_gap
;
221 case THINTHICK_LARGEGAP
:
222 return fWidth
+ THINTHICK_LARGEGAP_line1
+ THINTHICK_LARGEGAP_line2
;
224 case THICKTHIN_SMALLGAP
:
225 return fWidth
+ THICKTHIN_SMALLGAP_line1
+ THICKTHIN_SMALLGAP_gap
;
227 case THICKTHIN_LARGEGAP
:
228 return fWidth
+ THICKTHIN_LARGEGAP_line1
+ THICKTHIN_LARGEGAP_line2
;
231 return (fWidth
* 2.0) + OUTSET_line1
;
234 return (fWidth
* 2.0) + INSET_line2
;
237 assert(false); // should only be called for known border style
243 ConvertBorderWidthToWord(SvxBorderStyle
const eStyle
, double const fWidth
)
258 case THINTHICK_MEDIUMGAP
:
259 case THICKTHIN_MEDIUMGAP
:
264 case THINTHICK_SMALLGAP
:
265 return fWidth
- THINTHICK_SMALLGAP_line2
- THINTHICK_SMALLGAP_gap
;
267 case THINTHICK_LARGEGAP
:
268 return fWidth
- THINTHICK_LARGEGAP_line1
- THINTHICK_LARGEGAP_line2
;
270 case THICKTHIN_SMALLGAP
:
271 return fWidth
- THICKTHIN_SMALLGAP_line1
- THICKTHIN_SMALLGAP_gap
;
273 case THICKTHIN_LARGEGAP
:
274 return fWidth
- THICKTHIN_LARGEGAP_line1
- THICKTHIN_LARGEGAP_line2
;
277 return (fWidth
- OUTSET_line1
) / 2.0;
280 return (fWidth
- INSET_line2
) / 2.0;
283 assert(false); // should only be called for known border style
288 /** Get the BorderWithImpl object corresponding to the given #nStyle, all the
289 units handled by the resulting object are Twips and the
290 BorderWidthImpl::GetLine1() corresponds to the Outer Line.
292 BorderWidthImpl
SvxBorderLine::getWidthImpl( SvxBorderStyle nStyle
)
294 BorderWidthImpl aImpl
;
300 aImpl
= BorderWidthImpl( 0, 0.0 );
308 aImpl
= BorderWidthImpl( CHANGE_LINE1
, 1.0 );
314 aImpl
= BorderWidthImpl(
315 CHANGE_LINE1
| CHANGE_LINE2
| CHANGE_DIST
,
316 // fdo#46112 fdo#38542 fdo#43249:
317 // non-constant witdths must sum to 1
318 1.0/3.0, 1.0/3.0, 1.0/3.0 );
321 case THINTHICK_SMALLGAP
:
322 aImpl
= BorderWidthImpl( CHANGE_LINE1
, 1.0,
323 THINTHICK_SMALLGAP_line2
, THINTHICK_SMALLGAP_gap
);
326 case THINTHICK_MEDIUMGAP
:
327 aImpl
= BorderWidthImpl(
328 CHANGE_LINE1
| CHANGE_LINE2
| CHANGE_DIST
,
332 case THINTHICK_LARGEGAP
:
333 aImpl
= BorderWidthImpl( CHANGE_DIST
,
334 THINTHICK_LARGEGAP_line1
, THINTHICK_LARGEGAP_line2
, 1.0 );
337 case THICKTHIN_SMALLGAP
:
338 aImpl
= BorderWidthImpl( CHANGE_LINE2
, THICKTHIN_SMALLGAP_line1
,
339 1.0, THICKTHIN_SMALLGAP_gap
);
342 case THICKTHIN_MEDIUMGAP
:
343 aImpl
= BorderWidthImpl(
344 CHANGE_LINE1
| CHANGE_LINE2
| CHANGE_DIST
,
348 case THICKTHIN_LARGEGAP
:
349 aImpl
= BorderWidthImpl( CHANGE_DIST
, THICKTHIN_LARGEGAP_line1
,
350 THICKTHIN_LARGEGAP_line2
, 1.0 );
353 // Engraved / Embossed
355 * Word compat: the lines widths are exactly following this rule, shouldbe:
356 * 0.75pt up to 3pt and then 3pt
361 aImpl
= BorderWidthImpl(
362 CHANGE_LINE1
| CHANGE_LINE2
| CHANGE_DIST
,
368 * Word compat: the gap width should be measured relatively to the biggest width for the
372 aImpl
= BorderWidthImpl(
373 CHANGE_LINE2
| CHANGE_DIST
,
374 OUTSET_line1
, 0.5, 0.5 );
378 aImpl
= BorderWidthImpl(
379 CHANGE_LINE1
| CHANGE_DIST
,
380 0.5, INSET_line2
, 0.5 );
387 // -----------------------------------------------------------------------
389 SvxBorderLine::SvxBorderLine( const SvxBorderLine
& r
)
394 // -----------------------------------------------------------------------
396 SvxBorderLine
& SvxBorderLine::operator=( const SvxBorderLine
& r
)
399 m_nWidth
= r
.m_nWidth
;
400 m_aWidthImpl
= r
.m_aWidthImpl
;
401 m_bMirrorWidths
= r
.m_bMirrorWidths
;
404 m_nStyle
= r
.m_nStyle
;
405 m_bUseLeftTop
= r
.m_bUseLeftTop
;
406 m_pColorOutFn
= r
.m_pColorOutFn
;
407 m_pColorInFn
= r
.m_pColorInFn
;
408 m_pColorGapFn
= r
.m_pColorGapFn
;
412 // -----------------------------------------------------------------------
414 void SvxBorderLine::ScaleMetrics( long nMult
, long nDiv
)
420 void SvxBorderLine::GuessLinesWidths( SvxBorderStyle nStyle
, sal_uInt16 nOut
, sal_uInt16 nIn
, sal_uInt16 nDist
)
425 if ( nOut
> 0 && nIn
> 0 )
429 if ( nStyle
== DOUBLE
)
431 static SvxBorderStyle aDoubleStyles
[] =
442 size_t const len
= SAL_N_ELEMENTS(aDoubleStyles
);
444 SvxBorderStyle
nTestStyle(NONE
);
445 for (size_t i
= 0; i
< len
&& nWidth
== 0; ++i
)
447 nTestStyle
= aDoubleStyles
[i
];
448 BorderWidthImpl aWidthImpl
= getWidthImpl( nTestStyle
);
449 nWidth
= aWidthImpl
.GuessWidth( nOut
, nIn
, nDist
);
452 // If anything matched, then set it
456 SetBorderLineStyle(nStyle
);
461 // fdo#38542: not a known double, default to something custom...
462 SetBorderLineStyle(nStyle
);
463 m_nWidth
= nOut
+ nIn
+ nDist
;
464 if (nOut
+ nIn
+ nDist
)
466 m_aWidthImpl
= BorderWidthImpl(
467 CHANGE_LINE1
| CHANGE_LINE2
| CHANGE_DIST
,
468 static_cast<double>(nOut
) / static_cast<double>(m_nWidth
),
469 static_cast<double>(nIn
) / static_cast<double>(m_nWidth
),
470 static_cast<double>(nDist
) / static_cast<double>(m_nWidth
));
476 SetBorderLineStyle(nStyle
);
477 if (nOut
== 0 && nIn
> 0)
479 // If only inner width is given swap inner and outer widths for
480 // single line styles, otherwise GuessWidth() marks this as invalid
481 // and returns a 0 width.
488 ::std::swap( nOut
, nIn
);
494 m_nWidth
= m_aWidthImpl
.GuessWidth( nOut
, nIn
, nDist
);
498 sal_uInt16
SvxBorderLine::GetOutWidth() const
500 sal_uInt16 nOut
= (sal_uInt16
)Scale( m_aWidthImpl
.GetLine1( m_nWidth
), m_nMult
, m_nDiv
);
501 if ( m_bMirrorWidths
)
502 nOut
= (sal_uInt16
)Scale( m_aWidthImpl
.GetLine2( m_nWidth
), m_nMult
, m_nDiv
);
506 sal_uInt16
SvxBorderLine::GetInWidth() const
508 sal_uInt16 nIn
= (sal_uInt16
)Scale( m_aWidthImpl
.GetLine2( m_nWidth
), m_nMult
, m_nDiv
);
509 if ( m_bMirrorWidths
)
510 nIn
= (sal_uInt16
)Scale( m_aWidthImpl
.GetLine1( m_nWidth
), m_nMult
, m_nDiv
);
514 sal_uInt16
SvxBorderLine::GetDistance() const
516 return (sal_uInt16
)Scale( m_aWidthImpl
.GetGap( m_nWidth
), m_nMult
, m_nDiv
);
519 // -----------------------------------------------------------------------
521 sal_Bool
SvxBorderLine::operator==( const SvxBorderLine
& rCmp
) const
523 return ( ( aColor
== rCmp
.aColor
) &&
524 ( m_nWidth
== rCmp
.m_nWidth
) &&
525 ( m_bMirrorWidths
== rCmp
.m_bMirrorWidths
) &&
526 ( m_aWidthImpl
== rCmp
.m_aWidthImpl
) &&
527 ( m_nStyle
== rCmp
.GetBorderLineStyle()) &&
528 ( m_bUseLeftTop
== rCmp
.m_bUseLeftTop
) &&
529 ( m_pColorOutFn
== rCmp
.m_pColorOutFn
) &&
530 ( m_pColorInFn
== rCmp
.m_pColorInFn
) &&
531 ( m_pColorGapFn
== rCmp
.m_pColorGapFn
) );
534 void SvxBorderLine::SetBorderLineStyle( SvxBorderStyle nNew
)
537 m_aWidthImpl
= getWidthImpl( m_nStyle
);
542 m_pColorOutFn
= threeDLightColor
;
543 m_pColorInFn
= threeDDarkColor
;
544 m_pColorGapFn
= threeDMediumColor
;
545 m_bUseLeftTop
= true;
548 m_pColorOutFn
= threeDDarkColor
;
549 m_pColorInFn
= threeDLightColor
;
550 m_pColorGapFn
= threeDMediumColor
;
551 m_bUseLeftTop
= true;
554 m_pColorOutFn
= lightColor
;
555 m_pColorInFn
= darkColor
;
556 m_bUseLeftTop
= true;
557 m_pColorGapFn
= NULL
;
560 m_pColorOutFn
= darkColor
;
561 m_pColorInFn
= lightColor
;
562 m_bUseLeftTop
= true;
563 m_pColorGapFn
= NULL
;
566 m_pColorOutFn
= darkColor
;
567 m_pColorInFn
= darkColor
;
568 m_bUseLeftTop
= false;
569 m_pColorGapFn
= NULL
;
574 Color
SvxBorderLine::GetColorOut( bool bLeftOrTop
) const
576 Color aResult
= aColor
;
578 if ( m_aWidthImpl
.IsDouble() && m_pColorOutFn
!= NULL
)
580 if ( !bLeftOrTop
&& m_bUseLeftTop
)
581 aResult
= (*m_pColorInFn
)( aColor
);
583 aResult
= (*m_pColorOutFn
)( aColor
);
589 Color
SvxBorderLine::GetColorIn( bool bLeftOrTop
) const
591 Color aResult
= aColor
;
593 if ( m_aWidthImpl
.IsDouble() && m_pColorInFn
!= NULL
)
595 if ( !bLeftOrTop
&& m_bUseLeftTop
)
596 aResult
= (*m_pColorOutFn
)( aColor
);
598 aResult
= (*m_pColorInFn
)( aColor
);
604 Color
SvxBorderLine::GetColorGap( ) const
606 Color aResult
= aColor
;
608 if ( m_aWidthImpl
.IsDouble() && m_pColorGapFn
!= NULL
)
610 aResult
= (*m_pColorGapFn
)( aColor
);
616 // -----------------------------------------------------------------------
618 XubString
SvxBorderLine::GetValueString( SfxMapUnit eSrcUnit
,
619 SfxMapUnit eDestUnit
,
620 const IntlWrapper
* pIntl
,
621 sal_Bool bMetricStr
) const
623 static const sal_uInt16 aStyleIds
[] =
629 RID_THINTHICK_SMALLGAP
,
630 RID_THINTHICK_MEDIUMGAP
,
631 RID_THINTHICK_LARGEGAP
,
632 RID_THICKTHIN_SMALLGAP
,
633 RID_THICKTHIN_MEDIUMGAP
,
634 RID_THICKTHIN_LARGEGAP
,
640 sal_uInt16 nResId
= aStyleIds
[m_nStyle
];
642 aStr
+= sal_Unicode('(');
643 aStr
+= ::GetColorString( aColor
);
647 aStr
+= EE_RESSTR(nResId
);
650 String sMetric
= EE_RESSTR(GetMetricId( eDestUnit
));
651 aStr
+= GetMetricText( (long)GetInWidth(), eSrcUnit
, eDestUnit
, pIntl
);
655 aStr
+= GetMetricText( (long)GetOutWidth(), eSrcUnit
, eDestUnit
, pIntl
);
659 aStr
+= GetMetricText( (long)GetDistance(), eSrcUnit
, eDestUnit
, pIntl
);
663 aStr
+= sal_Unicode(')');
667 bool SvxBorderLine::HasPriority( const SvxBorderLine
& rOtherLine
) const
669 const sal_uInt16 nThisSize
= GetOutWidth() + GetDistance() + GetInWidth();
670 const sal_uInt16 nOtherSize
= rOtherLine
.GetOutWidth() + rOtherLine
.GetDistance() + rOtherLine
.GetInWidth();
672 if ( nThisSize
> nOtherSize
)
676 else if ( nThisSize
< nOtherSize
)
680 else if ( rOtherLine
.GetInWidth() && !GetInWidth() )
688 bool operator!=( const SvxBorderLine
& rLeft
, const SvxBorderLine
& rRight
)
690 return !(rLeft
== rRight
);
693 } // namespace editeng
695 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */