1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "nel/gui/css_border_renderer.h"
20 #include "nel/gui/view_renderer.h"
21 #include "nel/gui/widget_manager.h"
24 using namespace NLMISC
;
32 // ----------------------------------------------------------------------------
33 CSSBorderRenderer::CSSBorderRenderer()
39 m_ModulateGlobalColor
= false;
42 m_MustComputeValues
= true;
50 m_RootFontSize
= 16.f
;
52 m_Computed
.Top
= m_Computed
.Right
= m_Computed
.Bottom
= m_Computed
.Left
= 0;
55 // ----------------------------------------------------------------------------
56 void CSSBorderRenderer::setRenderLayer(sint layer
)
58 m_RenderLayer
= layer
;
61 // ----------------------------------------------------------------------------
62 void CSSBorderRenderer::setModulateGlobalColor(bool s
)
64 m_ModulateGlobalColor
= s
;
67 // ----------------------------------------------------------------------------
68 void CSSBorderRenderer::setRect(sint32 x
, sint32 y
, sint32 w
, sint32 h
)
75 m_Dirty
= (w
> 0 && h
> 0);
78 // ----------------------------------------------------------------------------
79 bool CSSBorderRenderer::hasInnerShape(CSSLineStyle style
) const
81 return style
== CSS_LINE_STYLE_DOUBLE
||
82 style
== CSS_LINE_STYLE_GROOVE
||
83 style
== CSS_LINE_STYLE_RIDGE
;
86 // ----------------------------------------------------------------------------
87 void CSSBorderRenderer::computeValues()
89 m_MustComputeValues
= false;
91 // TODO :should save as computed value
96 vpW
= m_Viewport
->getWReal();
97 vpH
= m_Viewport
->getHReal();
100 m_Computed
.Top
= m_Border
.Top
.empty() ? 0 : m_Border
.Top
.Width
.calculate(0, m_FontSize
, m_RootFontSize
, vpW
, vpH
);
101 m_Computed
.Right
= m_Border
.Right
.empty() ? 0 : m_Border
.Right
.Width
.calculate(0, m_FontSize
, m_RootFontSize
, vpW
, vpH
);
102 m_Computed
.Bottom
= m_Border
.Bottom
.empty() ? 0 : m_Border
.Bottom
.Width
.calculate(0, m_FontSize
, m_RootFontSize
, vpW
, vpH
);
103 m_Computed
.Left
= m_Border
.Left
.empty() ? 0 : m_Border
.Left
.Width
.calculate(0, m_FontSize
, m_RootFontSize
, vpW
, vpH
);
106 // ----------------------------------------------------------------------------
107 void CSSBorderRenderer::getAdjacentBorders(EBorderSide side
, EBorderSide
&adjBorderL
, EBorderSide
&adjBorderR
) const
112 adjBorderL
= BORDER_TOP_LEFT
;
113 adjBorderR
= BORDER_TOP_RIGHT
;
116 adjBorderL
= BORDER_RIGHT_BOTTOM
;
117 adjBorderR
= BORDER_RIGHT_TOP
;
120 adjBorderL
= BORDER_BOTTOM_LEFT
;
121 adjBorderR
= BORDER_BOTTOM_RIGHT
;
124 adjBorderL
= BORDER_LEFT_BOTTOM
;
125 adjBorderR
= BORDER_LEFT_TOP
;
128 adjBorderL
= adjBorderR
= BORDER_INVALID
;
133 // ----------------------------------------------------------------------------
134 void CSSBorderRenderer::getAdjacentBorderWidth(EBorderSide side
, sint32
&adjWidthL
, sint32
&adjWidthR
) const
140 adjWidthL
= m_Computed
.Left
;
141 adjWidthR
= m_Computed
.Right
;
145 adjWidthL
= m_Computed
.Bottom
;
146 adjWidthR
= m_Computed
.Top
;
149 adjWidthL
= adjWidthR
= 0;
154 // ----------------------------------------------------------------------------
155 void CSSBorderRenderer::buildDotCornerStart(EBorderSide side
, SDrawBorder shape
, float x1
, float y1
, float radius
)
161 line
.V0
.set(m_XReal
+ m_Computed
.Left
, m_YReal
+ m_HReal
- m_Computed
.Top
, 0);
162 line
.V1
.set(m_XReal
, m_YReal
+ m_HReal
, 0);
163 buildDotCorner(shape
, x1
, y1
, radius
, line
);
166 line
.V0
.set(m_XReal
+ m_WReal
, m_YReal
, 0);
167 line
.V1
.set(m_XReal
+ m_WReal
- m_Computed
.Right
, m_YReal
+ m_Computed
.Bottom
, 0);
168 buildDotCorner(shape
, x1
, y1
, radius
, line
);
171 line
.V0
.set(m_XReal
, m_YReal
, 0);
172 line
.V1
.set(m_XReal
+ m_Computed
.Left
, m_YReal
+ m_Computed
.Bottom
, 0);
173 buildDotCorner(shape
, x1
, y1
, radius
, line
);
176 line
.V0
.set(m_XReal
+ m_Computed
.Left
, m_YReal
+ m_Computed
.Bottom
, 0);
177 line
.V1
.set(m_XReal
, m_YReal
, 0);
178 buildDotCorner(shape
, x1
, y1
, radius
, line
);
183 // ----------------------------------------------------------------------------
184 void CSSBorderRenderer::buildDotCornerEnd(EBorderSide side
, SDrawBorder shape
, float x1
, float y1
, float radius
)
190 line
.V0
.set(m_XReal
+ m_WReal
, m_YReal
+ m_HReal
, 0);
191 line
.V1
.set(m_XReal
+ m_WReal
- m_Computed
.Right
, m_YReal
+ m_HReal
- m_Computed
.Top
, 0);
192 buildDotCorner(shape
, x1
, y1
, radius
, line
);
195 line
.V0
.set(m_XReal
+ m_WReal
- m_Computed
.Right
, m_YReal
+ m_HReal
- m_Computed
.Top
, 0);
196 line
.V1
.set(m_XReal
+ m_WReal
, m_YReal
+ m_HReal
, 0);
197 buildDotCorner(shape
, x1
, y1
, radius
, line
);
200 line
.V0
.set(m_XReal
+ m_WReal
- m_Computed
.Right
, m_YReal
+ m_Computed
.Bottom
, 0);
201 line
.V1
.set(m_XReal
+ m_WReal
, m_YReal
, 0);
202 buildDotCorner(shape
, x1
, y1
, radius
, line
);
205 line
.V0
.set(m_XReal
, m_YReal
+ m_HReal
, 0);
206 line
.V1
.set(m_XReal
+ m_Computed
.Left
, m_YReal
+ m_HReal
- m_Computed
.Top
, 0);
207 buildDotCorner(shape
, x1
, y1
, radius
, line
);
212 // ----------------------------------------------------------------------------
213 void CSSBorderRenderer::buildDashedBorder(EBorderSide side
)
219 sint32 width
, thickness
;
224 border
= m_Border
.Top
;
226 thickness
= m_Computed
.Top
;
228 y
= m_YReal
+ m_HReal
- thickness
;
232 border
= m_Border
.Right
;
234 thickness
= m_Computed
.Right
;
235 x
= m_XReal
+ m_WReal
- thickness
;
240 border
= m_Border
.Bottom
;
242 thickness
= m_Computed
.Bottom
;
248 border
= m_Border
.Left
;
250 thickness
= m_Computed
.Left
;
258 if (width
< 1) return;
259 if (thickness
< 1) return;
262 shape
.Color
= border
.Color
;
263 shape
.Quad
.Uv0
.set(0.f
, 0.f
);
264 shape
.Quad
.Uv1
.set(1.f
, 0.f
);
265 shape
.Quad
.Uv2
.set(1.f
, 1.f
);
266 shape
.Quad
.Uv3
.set(0.f
, 1.f
);
268 EBorderSide adjBorderL
, adjBorderR
;
269 getAdjacentBorders(side
, adjBorderL
, adjBorderR
);
271 sint32 adjWidthL
, adjWidthR
;
272 getAdjacentBorderWidth(side
, adjWidthL
, adjWidthR
);
275 float &xy
= horizontal
? x
: y
;
277 if (border
.Style
== CSS_LINE_STYLE_DOTTED
)
279 // thick border with little or no content might try to draw larger dot that fits
280 float radius
= std::min(thickness
/ 2.f
, width
/ 2.f
);
281 float dot
= thickness
;
283 sint32 count
= std::floor((float)width
/ dot
);
284 // 3n (dot, gap, dot) groups; count should be odd
285 if ((count
% 2) == 0) count
+= 1;
289 // fallback to single dot
301 buildDotSegments(shape
, x
, y
, radius
);
305 // center-to-center spacing for dots
306 float spacing
= dot
+ (width
- dot
* count
) / (count
-1);
312 buildDotCornerStart(side
, shape
, x
, y
, radius
);
314 buildDotSegments(shape
, x
, y
, radius
);
326 buildDotSegments(shape
, x
, y
, radius
);
334 buildDotCornerEnd(side
, shape
, x
, y
, radius
);
338 sint32 innerWidth
= width
;
339 if (adjWidthL
> 0) innerWidth
-= adjWidthL
;
340 if (adjWidthR
> 0) innerWidth
-= adjWidthR
;
342 sint32 count
= std::floor((float)innerWidth
* 2.f
/ (thickness
* 3));
344 if ((float)innerWidth
< 2.f
* thickness
)
346 buildSolidBorder(side
);
350 // 4n groups (halfDash, halfGap, halfGap, halfDash)
351 if ((count
% 4) == 1) count
+= 3;
352 else if ((count
% 4) == 2) count
+= 2;
353 else if ((count
% 4) == 3) count
+= 1;
355 float halfDash
= (float)innerWidth
/ (float)count
;
356 float fullDash
= halfDash
* 2.f
;
358 // draw half dash or full corner
359 makeBorderQuad(side
, shape
, x
, y
, adjWidthL
+ halfDash
, thickness
);
361 makeCornerQuad(adjBorderL
, shape
);
362 m_DrawBorders
.push_back(shape
);
363 xy
+= adjWidthL
+ halfDash
;
365 // start/end half dash that are merged with corners
373 makeBorderQuad(side
, shape
, x
, y
, fullDash
, thickness
);
374 m_DrawBorders
.push_back(shape
);
382 // draw half dash or full corner
383 makeBorderQuad(side
, shape
, x
, y
, adjWidthR
+ halfDash
, thickness
);
385 makeCornerQuad(adjBorderR
, shape
);
387 m_DrawBorders
.push_back(shape
);
391 // ----------------------------------------------------------------------------
392 void CSSBorderRenderer::buildSolidBorder(EBorderSide side
)
395 sint width
, thickness
;
400 border
= m_Border
.Top
;
402 thickness
= m_Computed
.Top
;
404 y
= m_YReal
+ m_HReal
- thickness
;
407 border
= m_Border
.Right
;
409 thickness
= m_Computed
.Right
;
410 x
= m_XReal
+ m_WReal
- thickness
;
414 border
= m_Border
.Bottom
;
416 thickness
= m_Computed
.Bottom
;
421 border
= m_Border
.Left
;
423 thickness
= m_Computed
.Left
;
432 shape
.Color
= border
.Color
;
433 shape
.Quad
.Uv0
.set(0.f
, 0.f
);
434 shape
.Quad
.Uv1
.set(1.f
, 0.f
);
435 shape
.Quad
.Uv2
.set(1.f
, 1.f
);
436 shape
.Quad
.Uv3
.set(0.f
, 1.f
);
438 if (border
.Style
== CSS_LINE_STYLE_INSET
&& (side
== BORDER_TOP
|| side
== BORDER_LEFT
))
439 shape
.Color
= blend(border
.Color
, CRGBA::Black
, 0.5f
);
440 else if (border
.Style
== CSS_LINE_STYLE_OUTSET
&& (side
== BORDER_BOTTOM
|| side
== BORDER_RIGHT
))
441 shape
.Color
= blend(border
.Color
, CRGBA::Black
, 0.5f
);
445 EBorderSide adjBorderL
, adjBorderR
;
446 getAdjacentBorders(side
, adjBorderL
, adjBorderR
);
448 makeBorderQuad(side
, shape
, x
, y
, width
, thickness
);
449 makeCornerQuad(adjBorderL
, shape
);
450 makeCornerQuad(adjBorderR
, shape
);
452 m_DrawBorders
.push_back(shape
);
455 if (hasInnerShape(border
.Style
))
457 if (side
== BORDER_TOP
|| side
== BORDER_LEFT
)
459 if (border
.Style
== CSS_LINE_STYLE_GROOVE
)
460 m_DrawBorders
.back().Color
= blend(border
.Color
, CRGBA::Black
, 0.5f
);
461 else if (border
.Style
== CSS_LINE_STYLE_RIDGE
)
462 shape
.Color
= blend(border
.Color
, CRGBA::Black
, 0.5f
);
464 else if (side
== BORDER_BOTTOM
|| side
== BORDER_RIGHT
)
466 if (border
.Style
== CSS_LINE_STYLE_GROOVE
)
467 shape
.Color
= blend(border
.Color
, CRGBA::Black
, 0.5f
);
468 else if (border
.Style
== CSS_LINE_STYLE_RIDGE
)
469 m_DrawBorders
.back().Color
= blend(border
.Color
, CRGBA::Black
, 0.5f
);
472 sint32 adjWidthL
, adjWidthR
;
473 getAdjacentBorderWidth(side
, adjWidthL
, adjWidthR
);
475 float iStart
, iMiddle
, iEnd
;
476 if (border
.Style
== CSS_LINE_STYLE_DOUBLE
)
478 iStart
= 2 * adjWidthL
/ 3.f
;
479 iMiddle
= 2 * thickness
/ 3.f
;
480 iEnd
= 2 * adjWidthR
/ 3.f
;
482 iStart
= adjWidthL
/ 2.f
;
483 iMiddle
= thickness
/ 2.f
;
484 iEnd
= adjWidthR
/ 2.f
;
487 // create inner shape and remove overlapping from outer shape
491 m_DrawBorders
.back().Quad
.V0
.x
-= iStart
; m_DrawBorders
.back().Quad
.V0
.y
+= iMiddle
;
492 m_DrawBorders
.back().Quad
.V1
.x
+= iEnd
; m_DrawBorders
.back().Quad
.V1
.y
+= iMiddle
;
493 shape
.Quad
.V3
.x
+= iStart
; shape
.Quad
.V3
.y
-= iMiddle
;
494 shape
.Quad
.V2
.x
-= iEnd
; shape
.Quad
.V2
.y
-= iMiddle
;
497 m_DrawBorders
.back().Quad
.V2
.x
+= iEnd
; m_DrawBorders
.back().Quad
.V2
.y
-= iMiddle
;
498 m_DrawBorders
.back().Quad
.V3
.x
-= iStart
; m_DrawBorders
.back().Quad
.V3
.y
-= iMiddle
;
499 shape
.Quad
.V1
.x
-= iEnd
; shape
.Quad
.V1
.y
+= iMiddle
;
500 shape
.Quad
.V0
.x
+= iStart
; shape
.Quad
.V0
.y
+= iMiddle
;
503 m_DrawBorders
.back().Quad
.V3
.x
+= iMiddle
; m_DrawBorders
.back().Quad
.V3
.y
+= iEnd
;
504 m_DrawBorders
.back().Quad
.V0
.x
+= iMiddle
; m_DrawBorders
.back().Quad
.V0
.y
-= iStart
;
505 shape
.Quad
.V2
.x
-= iMiddle
; shape
.Quad
.V2
.y
-= iEnd
;
506 shape
.Quad
.V1
.x
-= iMiddle
; shape
.Quad
.V1
.y
+= iStart
;
509 m_DrawBorders
.back().Quad
.V2
.x
-= iMiddle
; m_DrawBorders
.back().Quad
.V2
.y
+= iEnd
;
510 m_DrawBorders
.back().Quad
.V1
.x
-= iMiddle
; m_DrawBorders
.back().Quad
.V1
.y
-= iStart
;
511 shape
.Quad
.V3
.x
+= iMiddle
; shape
.Quad
.V3
.y
-= iEnd
;
512 shape
.Quad
.V0
.x
+= iMiddle
; shape
.Quad
.V0
.y
+= iStart
;
515 m_DrawBorders
.push_back(shape
);
519 // ----------------------------------------------------------------------------
520 void CSSBorderRenderer::makeBorderQuad(EBorderSide side
, SDrawBorder
&shape
, float x
, float y
, float width
, float thickness
) const
525 case BORDER_TOP
: quadW
= width
; quadH
= thickness
; break;
526 case BORDER_BOTTOM
:quadW
= width
; quadH
= thickness
; break;
527 case BORDER_LEFT
: quadW
= thickness
; quadH
= width
; break;
528 case BORDER_RIGHT
: quadW
= thickness
; quadH
= width
; break;
531 shape
.Quad
.V3
.x
= x
; shape
.Quad
.V3
.y
= y
+ quadH
;
532 shape
.Quad
.V2
.x
= x
+ quadW
; shape
.Quad
.V2
.y
= y
+ quadH
;
533 shape
.Quad
.V1
.x
= x
+ quadW
; shape
.Quad
.V1
.y
= y
;
534 shape
.Quad
.V0
.x
= x
; shape
.Quad
.V0
.y
= y
;
537 // ----------------------------------------------------------------------------
538 void CSSBorderRenderer::makeCornerQuad(EBorderSide side
, SDrawBorder
&shape
) const
542 case BORDER_TOP_LEFT
: shape
.Quad
.V0
.x
+= m_Computed
.Left
; break;
543 case BORDER_TOP_RIGHT
: shape
.Quad
.V1
.x
-= m_Computed
.Right
; break;
544 case BORDER_RIGHT_TOP
: shape
.Quad
.V3
.y
-= m_Computed
.Top
; break;
545 case BORDER_RIGHT_BOTTOM
: shape
.Quad
.V0
.y
+= m_Computed
.Bottom
; break;
546 case BORDER_BOTTOM_LEFT
: shape
.Quad
.V3
.x
+= m_Computed
.Left
; break;
547 case BORDER_BOTTOM_RIGHT
: shape
.Quad
.V2
.x
-= m_Computed
.Right
; break;
548 case BORDER_LEFT_TOP
: shape
.Quad
.V2
.y
-= m_Computed
.Top
; break;
549 case BORDER_LEFT_BOTTOM
: shape
.Quad
.V1
.y
+= m_Computed
.Bottom
; break;
553 // ----------------------------------------------------------------------------
554 static bool getCircleLineIntersection(float x
, float y
, float r
, const NLMISC::CLine
&line
, NLMISC::CLine
&result
)
556 float dx
= line
.V0
.x
- line
.V1
.x
;
557 float dy
= line
.V0
.y
- line
.V1
.y
;
558 float rx
= line
.V0
.x
-x
;
559 float ry
= line
.V0
.y
-y
;
560 float a
= dx
*dx
+ dy
*dy
;
561 float b
= 2*(dx
* rx
+ dy
* ry
);
562 float c
= rx
* rx
+ ry
* ry
- r
*r
;
563 float d
= b
*b
- 4 * a
* c
;
570 // single intersection
571 //float t = -b / (2*a);
572 //result.V0.x = result.V1.x = line.V0.x + t * dx;
573 //result.V0.y = result.V1.y = line.V0.y + t * dy;
578 t
= (-b
+ sqrt(d
)) / (2 * a
);
579 result
.V0
.x
= line
.V0
.x
+ t
* dx
;
580 result
.V0
.y
= line
.V0
.y
+ t
* dy
;
582 t
= (-b
- sqrt(d
)) / (2 * a
);
583 result
.V1
.x
= line
.V0
.x
+ t
* dx
;
584 result
.V1
.y
= line
.V0
.y
+ t
* dy
;
589 // ----------------------------------------------------------------------------
590 void CSSBorderRenderer::buildDotCorner(SDrawBorder shape
, float cX
, float cY
, float cR
, const NLMISC::CLine
&line
)
592 static const float twopi
= 2 * NLMISC::Pi
;
594 if (getCircleLineIntersection(cX
, cY
, cR
, line
, out
))
596 float fromAngle
= std::atan2(out
.V0
.y
- cY
, out
.V0
.x
- cX
);
597 float toAngle
= std::atan2(out
.V1
.y
- cY
, out
.V1
.x
- cX
);
598 if (fromAngle
< 0) fromAngle
+= twopi
;
599 if (toAngle
< 0) toAngle
+= twopi
;
602 buildDotSegments(shape
, cX
, cY
, cR
, fromAngle
, toAngle
);
604 buildDotSegments(shape
, cX
, cY
, cR
);
608 // ----------------------------------------------------------------------------
609 void CSSBorderRenderer::buildDotSegments(SDrawBorder shape
, float x
, float y
, float radius
, float fromAngle
, float toAngle
)
611 static const float pi
= (float)NLMISC::Pi
;
612 static const float twopi
= (float)(NLMISC::Pi
* 2);
613 static const uint minSectors
= 12;
615 // use single quad if dot is small
616 if (2 * radius
* m_Scale
< 4)
618 makeBorderQuad(BORDER_TOP
, shape
, x
- radius
, y
- radius
, radius
* 2, radius
* 2);
619 m_DrawBorders
.push_back(shape
);
623 // number of sectors for full circle
624 uint sectors
= std::max(minSectors
, (uint
)std::ceil(radius
* m_Scale
));
627 if (toAngle
< fromAngle
)
628 arcLength
= twopi
* (1 + toAngle
- fromAngle
);
630 arcLength
= twopi
* (toAngle
- fromAngle
);
633 float arcSectors
= ceil(arcLength
* sectors
/ twopi
);
634 float arcSectorLength
= arcLength
/ arcSectors
;
641 // only small segment is visible
642 float px1
= x
+ radius
* cosf(twopi
* fromAngle
);
643 float py1
= y
+ radius
* sinf(twopi
* fromAngle
);
644 float px2
= x
+ radius
* cosf(twopi
* toAngle
);
645 float py2
= y
+ radius
* sinf(twopi
* toAngle
);
646 float cx
= (px1
+ px2
) / 2.f
;
647 float cy
= (py1
+ py2
) / 2.f
;
648 shape
.Quad
.V0
.x
= cx
; shape
.Quad
.V0
.y
= cy
;
649 shape
.Quad
.V1
.x
= cx
; shape
.Quad
.V1
.y
= cy
;
653 shape
.Quad
.V0
.x
= x
; shape
.Quad
.V0
.y
= y
;
654 shape
.Quad
.V1
.x
= x
; shape
.Quad
.V1
.y
= y
;
657 float a1
= fromAngle
* twopi
;
659 for(step
= 0; step
< (uint
)arcSectors
; step
++)
661 float a2
= a1
+ arcSectorLength
;
663 shape
.Quad
.V2
.x
= x
+ radius
* cosf(a1
); shape
.Quad
.V2
.y
= y
+ radius
* sinf(a1
);
664 shape
.Quad
.V3
.x
= x
+ radius
* cosf(a2
); shape
.Quad
.V3
.y
= y
+ radius
* sinf(a2
);
666 m_DrawBorders
.push_back(shape
);
671 // build last sector if requested range is over 180deg
672 if (arcLength
> pi
&& arcLength
< twopi
)
674 float a2
= fromAngle
* twopi
;
675 shape
.Quad
.V2
.x
= x
+ radius
* cosf(a1
); shape
.Quad
.V2
.y
= y
+ radius
* sinf(a1
);
676 shape
.Quad
.V3
.x
= x
+ radius
* cosf(a2
); shape
.Quad
.V3
.y
= y
+ radius
* sinf(a2
);
677 m_DrawBorders
.push_back(shape
);
681 // ----------------------------------------------------------------------------
682 void CSSBorderRenderer::updateCoords()
685 m_DrawBorders
.clear();
687 if (m_MustComputeValues
)
690 if (m_Computed
.Top
> 0 && m_Border
.Top
.Color
.A
> 0)
692 if (m_Border
.Top
.Style
== CSS_LINE_STYLE_DASHED
|| m_Border
.Top
.Style
== CSS_LINE_STYLE_DOTTED
)
693 buildDashedBorder(BORDER_TOP
);
695 buildSolidBorder(BORDER_TOP
);
698 if (m_Computed
.Bottom
> 0 && m_Border
.Bottom
.Color
.A
> 0)
700 if (m_Border
.Bottom
.Style
== CSS_LINE_STYLE_DASHED
|| m_Border
.Bottom
.Style
== CSS_LINE_STYLE_DOTTED
)
701 buildDashedBorder(BORDER_BOTTOM
);
703 buildSolidBorder(BORDER_BOTTOM
);
706 if (m_Computed
.Right
> 0 && m_Border
.Right
.Color
.A
> 0)
708 if (m_Border
.Right
.Style
== CSS_LINE_STYLE_DASHED
|| m_Border
.Right
.Style
== CSS_LINE_STYLE_DOTTED
)
709 buildDashedBorder(BORDER_RIGHT
);
711 buildSolidBorder(BORDER_RIGHT
);
714 if (m_Computed
.Left
> 0 && m_Border
.Left
.Color
.A
> 0)
716 if (m_Border
.Left
.Style
== CSS_LINE_STYLE_DASHED
|| m_Border
.Left
.Style
== CSS_LINE_STYLE_DOTTED
)
717 buildDashedBorder(BORDER_LEFT
);
719 buildSolidBorder(BORDER_LEFT
);
724 // ----------------------------------------------------------------------------
725 void CSSBorderRenderer::draw() {
726 if (m_Dirty
) updateCoords();
727 if (m_DrawBorders
.empty()) return;
729 CViewRenderer
&rVR
= *CViewRenderer::getInstance();
732 if (m_ModulateGlobalColor
)
733 globalColor
= CWidgetManager::getInstance()->getGlobalColor();
735 sint32 texId
= rVR
.getBlankTextureId();
736 for(uint i
= 0; i
< m_DrawBorders
.size(); ++i
)
738 CRGBA color
= m_DrawBorders
[i
].Color
;
739 if (m_ModulateGlobalColor
)
740 color
.modulateFromColor (color
, globalColor
);
742 color
.A
= (uint8
) (((uint16
) CurrentAlpha
* (uint16
) color
.A
) >> 8);
743 rVR
.drawQuad(m_RenderLayer
, m_DrawBorders
[i
].Quad
, texId
, color
, false);