| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_svx.hxx" |
| #include <svx/framelink.hxx> |
| |
| #include <math.h> |
| #include <vcl/outdev.hxx> |
| #include <editeng/borderline.hxx> |
| |
| // ---------------------------------------------------------------------------- |
| |
| /** Define to select the drawing mode of thin dotted lines. |
| |
| 0 = Draw lines using an own implementation (recommended). Draws always |
| little dots in an appropriate distance. |
| 1 = Draw dotted lines using vcl/LineInfo. Results in dashed lines instead |
| of dotted lines, which may look ugly for diagonal lines. |
| */ |
| #define SVX_FRAME_USE_LINEINFO 0 |
| |
| // ---------------------------------------------------------------------------- |
| |
| #if SVX_FRAME_USE_LINEINFO |
| #include <vcl/lineinfo.hxx> |
| #endif |
| |
| namespace svx { |
| namespace frame { |
| |
| // ============================================================================ |
| // ============================================================================ |
| |
| namespace { |
| |
| typedef std::vector< Point > PointVec; |
| |
| // ---------------------------------------------------------------------------- |
| // Link result structs for horizontal and vertical lines and borders. |
| |
| /** Result struct used by the horizontal/vertical frame link functions. |
| |
| This struct is used to return coordinate offsets for one end of a single |
| line in a frame border, i.e. the left end of the primary line of a |
| horizontal frame border. |
| |
| 1) Usage for horizontal lines |
| |
| If this struct is returned by the lclLinkHorFrameBorder() function, each |
| member refers to the X coordinate of one edge of a single line end in a |
| horizontal frame border. They specify an offset to modify this coordinate |
| when the line is painted. The values in this struct may change a |
| rectangular line shape into a line with slanted left or right border, which |
| is used to connect the line with diagonal lines. |
| |
| Usage for a left line end: Usage for a right line end: |
| mnOffs1 mnOffs1 |
| <-------> <-------> |
| +-------------------------------+ |
| | the original horizontal line | |
| +-------------------------------+ |
| <-------> <-------> |
| mnOffs2 mnOffs2 |
| |
| 2) Usage for vertical lines |
| |
| If this struct is returned by the lclLinkVerFrameBorder() function, each |
| member refers to the Y coordinate of one edge of a single line end in a |
| vertical frame border. They specify an offset to modify this coordinate |
| when the line is painted. The values in this struct may change a |
| rectangular line shape into a line with slanted top or bottom border, which |
| is used to connect the line with diagonal lines. |
| |
| Usage for a top line end: mnOffs1 ^ ^ mnOffs2 |
| | +-------+ | |
| v | | v |
| | | |
| | | |
| the original vertical line ---> | | |
| | | |
| | | |
| ^ | | ^ |
| | +-------+ | |
| Usage for a bottom line end: mnOffs1 v v mnOffs2 |
| */ |
| struct LineEndResult |
| { |
| long mnOffs1; /// Offset for top or left edge, dependent of context. |
| long mnOffs2; /// Offset for bottom or right edge, dependent of context |
| |
| inline explicit LineEndResult() : mnOffs1( 0 ), mnOffs2( 0 ) {} |
| |
| inline void Swap() { std::swap( mnOffs1, mnOffs2 ); } |
| inline void Negate() { mnOffs1 = -mnOffs1; mnOffs2 = -mnOffs2; } |
| }; |
| |
| /** Result struct used by the horizontal/vertical frame link functions. |
| |
| This struct contains the linking results for one end of a frame border, |
| including both the primary and secondary line ends. |
| */ |
| struct BorderEndResult |
| { |
| LineEndResult maPrim; /// Result for primary line. |
| LineEndResult maSecn; /// Result for secondary line. |
| |
| inline void Negate() { maPrim.Negate(); maSecn.Negate(); } |
| }; |
| |
| /** Result struct used by the horizontal/vertical frame link functions. |
| |
| This struct contains the linking results for both frame border ends, and |
| therefore for the complete frame border. |
| */ |
| struct BorderResult |
| { |
| BorderEndResult maBeg; /// Result for begin of border line (left or top end). |
| BorderEndResult maEnd; /// Result for end of border line (right or bottom end). |
| }; |
| |
| // ---------------------------------------------------------------------------- |
| // Link result structs for diagonal lines and borders. |
| |
| /** Result struct used by the diagonal frame link functions. |
| |
| This struct contains the linking results for one line of a diagonal frame |
| border. |
| */ |
| struct DiagLineResult |
| { |
| long mnLClip; /// Offset for left border of clipping rectangle. |
| long mnRClip; /// Offset for right border of clipping rectangle. |
| long mnTClip; /// Offset for top border of clipping rectangle. |
| long mnBClip; /// Offset for bottom border of clipping rectangle. |
| |
| inline explicit DiagLineResult() : mnLClip( 0 ), mnRClip( 0 ), mnTClip( 0 ), mnBClip( 0 ) {} |
| }; |
| |
| /** Result struct used by the diagonal frame link functions. |
| |
| This struct contains the linking results for one diagonal frame border. |
| */ |
| struct DiagBorderResult |
| { |
| DiagLineResult maPrim; /// Result for primary line. |
| DiagLineResult maSecn; /// Result for secondary line. |
| }; |
| |
| /** Result struct used by the diagonal frame link functions. |
| |
| This struct contains the linking results for both diagonal frame borders. |
| */ |
| struct DiagBordersResult |
| { |
| DiagBorderResult maTLBR; /// Result for top-left to bottom-right frame border. |
| DiagBorderResult maBLTR; /// Result for bottom-left to top-right frame border. |
| }; |
| |
| // ---------------------------------------------------------------------------- |
| |
| /** A helper struct containing two points of a line. |
| */ |
| struct LinePoints |
| { |
| Point maBeg; /// Start position of the line. |
| Point maEnd; /// End position of the line. |
| |
| explicit LinePoints( const Point& rBeg, const Point& rEnd ) : |
| maBeg( rBeg ), maEnd( rEnd ) {} |
| explicit LinePoints( const Rectangle& rRect, bool bTLBR ) : |
| maBeg( bTLBR ? rRect.TopLeft() : rRect.TopRight() ), |
| maEnd( bTLBR ? rRect.BottomRight() : rRect.BottomLeft() ) {} |
| }; |
| |
| // ============================================================================ |
| |
| /** Rounds and casts a double value to a long value. */ |
| inline long lclD2L( double fValue ) |
| { |
| return static_cast< long >( (fValue < 0.0) ? (fValue - 0.5) : (fValue + 0.5) ); |
| } |
| |
| /** Converts a width in twips to a width in another map unit (specified by fScale). */ |
| sal_uInt16 lclScaleValue( long nValue, double fScale, sal_uInt16 nMaxWidth ) |
| { |
| // convert any width except 0 to at least 1 unit |
| // #i61324# 1 twip must scale to 1/100mm |
| return nValue ? static_cast< sal_uInt16 >( std::min< long >( std::max( |
| static_cast< long >( nValue * fScale ), 1L ), nMaxWidth ) ) : 0; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // Line width offset calculation. |
| |
| /** Returns the start offset of the single/primary line across the frame border. |
| |
| All following lclGet*Beg() and lclGet*End() functions return sub units to |
| increase the computational accuracy, where 256 sub units are equal to |
| 1 map unit of the used OutputDevice. |
| |
| The following pictures show the upper end of a vertical frame border and |
| illustrates the return values of all following lclGet*Beg() and lclGet*End() |
| functions. The first picture shows a single frame border, the second picture |
| shows a double frame border. |
| |
| The functions regard the reference point handling mode of the passed border |
| style. |
| REFMODE_CENTERED: |
| All returned offsets are relative to the middle position of the frame |
| border (offsets left of the middle are returned negative, offsets right |
| of the middle are returned positive). |
| REFMODE_BEGIN: |
| All returned offsets are relative to the begin of the frame border |
| (lclGetBeg() always returns 0). |
| REFMODE_END: |
| All returned offsets are relative to the end of the frame border |
| (lclGetEnd() always returns 0). |
| |
| |<- lclGetEnd() |
| |<- lclGetBeforeBeg() |<- lclGetPrimEnd() |
| | | |
| ||<- lclGetBeg() ||<- lclGetBehindEnd() |
| || || |
| |#################################| |
| direction of | ################################# |
| the frame | ################################# |
| border is | ################################# |
| vertical | ################################# |
| v ################################# |
| | |
| |<- middle of the frame border |
| |
| |
| lclGetDistEnd() ->||<- lclGetSecnBeg() |
| || |
| lclGetBeg() ->| lclGetDistBeg() ->| || |<- lclGetEnd() |
| | | || | |
| lclGetBeforeBeg()->|| lclGetPrimEnd() ->|| || ||<- lclGetBehindEnd() |
| || || || || |
| |######################| |#############| |
| direction of | ###################### ############# |
| the frame | ###################### ############# |
| border is | ###################### ############# |
| vertical | ###################### | ############# |
| v ###################### | ############# |
| primary line | secondary line |
| | |
| |<- middle of the frame border |
| |
| @return |
| The start offset of the single/primary line relative to the reference |
| position of the frame border (sub units; 0 for invisible or one pixel |
| wide single frame styles). |
| */ |
| long lclGetBeg( const Style& rBorder ) |
| { |
| long nPos = 0; |
| switch( rBorder.GetRefMode() ) |
| { |
| case REFMODE_CENTERED: if( rBorder.Prim() ) nPos = -128 * (rBorder.GetWidth() - 1); break; |
| case REFMODE_END: if( rBorder.Prim() ) nPos = -256 * (rBorder.GetWidth() - 1); break; |
| case REFMODE_BEGIN: break; |
| } |
| return nPos; |
| } |
| |
| /** Returns the end offset of the single/secondary line across the frame border. |
| @descr See description of lclGetBeg() for an illustration. |
| @return The end offset of the single/secondary line relative to the |
| reference position of the frame border (sub units; 0 for invisible or one |
| pixel wide single frame styles). */ |
| long lclGetEnd( const Style& rBorder ) |
| { |
| long nPos = 0; |
| switch( rBorder.GetRefMode() ) |
| { |
| case REFMODE_CENTERED: if( rBorder.Prim() ) nPos = 128 * (rBorder.GetWidth() - 1); break; |
| case REFMODE_BEGIN: if( rBorder.Prim() ) nPos = 256 * (rBorder.GetWidth() - 1); break; |
| case REFMODE_END: break; |
| } |
| return nPos; |
| } |
| |
| /** Returns the end offset of the primary line across the frame border. |
| @descr See description of lclGetBeg() for an illustration. |
| @return The end offset of the primary line relative to the reference |
| position of the frame border (sub units; the end of the primary line in a |
| double frame style, otherwise the same as lclGetEnd()). */ |
| inline long lclGetPrimEnd( const Style& rBorder ) |
| { return rBorder.Prim() ? (lclGetBeg( rBorder ) + 256 * (rBorder.Prim() - 1)) : 0; } |
| |
| /** Returns the start offset of the secondary line across the frame border. |
| @descr See description of lclGetBeg() for an illustration. |
| @return The start offset of the secondary line relative to the reference |
| position of the frame border (sub units; 0 for single/invisible border |
| styles). */ |
| inline long lclGetSecnBeg( const Style& rBorder ) |
| { return rBorder.Secn() ? (lclGetEnd( rBorder ) - 256 * (rBorder.Secn() - 1)) : 0; } |
| |
| /** Returns the start offset of the distance space across the frame border. |
| @descr See description of lclGetBeg() for an illustration. |
| @return The start offset of the distance space relative to the reference |
| position of the frame border (sub units; 0 for single/invisible border |
| styles). */ |
| inline long lclGetDistBeg( const Style& rBorder ) |
| { return rBorder.Secn() ? (lclGetBeg( rBorder ) + 256 * rBorder.Prim()) : 0; } |
| |
| /** Returns the end offset of the distance space across the frame border. |
| @descr See description of lclGetBeg() for an illustration. |
| @return The end offset of the distance space relative to the reference |
| position of the frame border (sub units; 0 for single/invisible border |
| styles). */ |
| inline long lclGetDistEnd( const Style& rBorder ) |
| { return rBorder.Secn() ? (lclGetEnd( rBorder ) - 256 * rBorder.Secn()) : 0; } |
| |
| /** Returns the offset before start of single/primary line across the frame border. |
| @descr See description of lclGetBeg() for an illustration. |
| @return The offset directly before start of single/primary line relative |
| to the reference position of the frame border (sub units; a value one less |
| than lclGetBeg() for visible frame styles, or 0 for invisible frame style). */ |
| inline long lclGetBeforeBeg( const Style& rBorder ) |
| { return rBorder.Prim() ? (lclGetBeg( rBorder ) - 256) : 0; } |
| |
| /** Returns the offset behind end of single/secondary line across the frame border. |
| @descr See description of lclGetBeg() for an illustration. |
| @return The offset directly behind end of single/secondary line relative |
| to the reference position of the frame border (sub units; a value one |
| greater than lclGetEnd() for visible frame styles, or 0 for invisible frame |
| style). */ |
| inline long lclGetBehindEnd( const Style& rBorder ) |
| { return rBorder.Prim() ? (lclGetEnd( rBorder ) + 256) : 0; } |
| |
| // ============================================================================ |
| // Linking functions |
| // ============================================================================ |
| |
| // ---------------------------------------------------------------------------- |
| // Linking of single horizontal line ends. |
| |
| /** Calculates X offsets for the left end of a single horizontal frame border. |
| |
| See DrawHorFrameBorder() function for a description of all parameters. |
| |
| @param rResult |
| (out-param) The contained values (sub units) specify offsets for the |
| X coordinates of the left line end. |
| */ |
| void lclLinkLeftEnd_Single( |
| LineEndResult& rResult, const Style& rBorder, |
| const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR ) |
| { |
| // both vertical and diagonal frame borders are double |
| if( rLFromT.Secn() && rLFromB.Secn() && rLFromTR.Secn() && rLFromBR.Secn() ) |
| { |
| // take left position of upper and lower secondary start |
| rResult.mnOffs1 = GetBLDiagOffset( lclGetBeg( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() ); |
| rResult.mnOffs2 = GetTLDiagOffset( lclGetEnd( rBorder ), lclGetSecnBeg( rLFromBR ), rLFromBR.GetAngle() ); |
| } |
| else |
| { |
| // both vertical frame borders are double |
| if( rLFromT.Secn() && rLFromB.Secn() ) |
| { |
| rResult.mnOffs1 = (!rLFromTR.Secn() && !rLFromBR.Secn() && (rLFromT.GetWidth() == rLFromB.GetWidth())) ? |
| // don't overdraw vertical borders with equal width |
| lclGetBehindEnd( rLFromT ) : |
| // take leftmost start of both secondary lines (#46488#) |
| std::min( lclGetSecnBeg( rLFromT ), lclGetSecnBeg( rLFromB ) ); |
| } |
| |
| // single border with equal width coming from left |
| else if( !rLFromL.Secn() && (rLFromL.Prim() == rBorder.Prim()) ) |
| // draw to connection point |
| rResult.mnOffs1 = 0; |
| |
| // single border coming from left |
| else if( !rLFromL.Secn() && rLFromL.Prim() ) |
| { |
| if( rLFromL.Prim() == rBorder.Prim() ) |
| // draw to reference position, if from left has equal width |
| rResult.mnOffs1 = 0; |
| else |
| rResult.mnOffs1 = (rLFromL < rBorder) ? |
| // take leftmost start of both frame borders, if from left is thinner |
| std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) ) : |
| // do not overdraw vertical, if from left is thicker |
| std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) ); |
| } |
| |
| // no border coming from left |
| else if( !rLFromL.Prim() ) |
| // don't overdraw vertical borders with equal width |
| rResult.mnOffs1 = (rLFromT.GetWidth() == rLFromB.GetWidth()) ? |
| lclGetBehindEnd( rLFromT ) : |
| std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) ); |
| |
| // double frame border coming from left and from top |
| else if( rLFromT.Secn() ) |
| // do not overdraw the vertical double frame border |
| rResult.mnOffs1 = lclGetBehindEnd( rLFromT ); |
| |
| // double frame border coming from left and from bottom |
| else if( rLFromB.Secn() ) |
| // do not overdraw the vertical double frame border |
| rResult.mnOffs1 = lclGetBehindEnd( rLFromB ); |
| |
| // double frame border coming from left, both vertical frame borders are single or off |
| else |
| // draw from leftmost start of both frame borders, if from left is not thicker |
| rResult.mnOffs1 = (rLFromL <= rBorder) ? |
| std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) ) : |
| std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) ); |
| |
| // bottom-left point is equal to top-left point (results in rectangle) |
| rResult.mnOffs2 = rResult.mnOffs1; |
| } |
| } |
| |
| /** Calculates X offsets for the left end of a primary horizontal line. |
| |
| See DrawHorFrameBorder() function for a description of all parameters. |
| |
| @param rResult |
| (out-param) The contained values (sub units) specify offsets for the |
| X coordinates of the left end of the primary line. |
| */ |
| void lclLinkLeftEnd_Prim( |
| LineEndResult& rResult, const Style& rBorder, |
| const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& /*rLFromBR*/ ) |
| { |
| // double diagonal frame border coming from top right |
| if( rLFromTR.Secn() ) |
| { |
| // draw from where secondary diagonal line meets the own primary |
| rResult.mnOffs1 = GetBLDiagOffset( lclGetBeg( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() ); |
| rResult.mnOffs2 = GetBLDiagOffset( lclGetPrimEnd( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() ); |
| } |
| |
| // no or single diagonal frame border - ignore it |
| else |
| { |
| // double frame border coming from top |
| if( rLFromT.Secn() ) |
| // draw from left edge of secondary vertical |
| rResult.mnOffs1 = lclGetSecnBeg( rLFromT ); |
| |
| // double frame border coming from left (from top is not double) |
| else if( rLFromL.Secn() ) |
| // do not overdraw single frame border coming from top |
| rResult.mnOffs1 = (rLFromL.GetWidth() == rBorder.GetWidth()) ? |
| 0 : lclGetBehindEnd( rLFromT ); |
| |
| // double frame border coming from bottom (from top and from left are not double) |
| else if( rLFromB.Secn() ) |
| // draw from left edge of primary vertical from bottom |
| rResult.mnOffs1 = lclGetBeg( rLFromB ); |
| |
| // no other frame border is double |
| else |
| // do not overdraw vertical frame borders |
| rResult.mnOffs1 = std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) ); |
| |
| // bottom-left point is equal to top-left point (results in rectangle) |
| rResult.mnOffs2 = rResult.mnOffs1; |
| } |
| } |
| |
| /** Calculates X offsets for the left end of a secondary horizontal line. |
| |
| See DrawHorFrameBorder() function for a description of all parameters. |
| |
| @param rResult |
| (out-param) The contained values (sub units) specify offsets for the |
| X coordinates of the left end of the secondary line. |
| */ |
| void lclLinkLeftEnd_Secn( |
| LineEndResult& rResult, const Style& rBorder, |
| const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR ) |
| { |
| /* Recycle lclLinkLeftEnd_Prim() function with mirrored horizontal borders. */ |
| lclLinkLeftEnd_Prim( rResult, rBorder.Mirror(), rLFromBR, rLFromB, rLFromL.Mirror(), rLFromT, rLFromTR ); |
| rResult.Swap(); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // Linking of horizontal frame border ends. |
| |
| /** Calculates X offsets for the left end of a horizontal frame border. |
| |
| This function can be used for single and double frame borders. |
| See DrawHorFrameBorder() function for a description of all parameters. |
| |
| @param rResult |
| (out-param) The contained values (sub units) specify offsets for the |
| X coordinates of the left end of the line(s) in the frame border. |
| */ |
| void lclLinkLeftEnd( |
| BorderEndResult& rResult, const Style& rBorder, |
| const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR ) |
| { |
| if( rBorder.Secn() ) |
| { |
| // current frame border is double |
| lclLinkLeftEnd_Prim( rResult.maPrim, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR ); |
| lclLinkLeftEnd_Secn( rResult.maSecn, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR ); |
| } |
| else if( rBorder.Prim() ) |
| { |
| // current frame border is single |
| lclLinkLeftEnd_Single( rResult.maPrim, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR ); |
| } |
| else |
| { |
| DBG_ERRORFILE( "lclLinkLeftEnd - called for invisible frame style" ); |
| } |
| } |
| |
| /** Calculates X offsets for the right end of a horizontal frame border. |
| |
| This function can be used for single and double frame borders. |
| See DrawHorFrameBorder() function for a description of all parameters. |
| |
| @param rResult |
| (out-param) The contained values (sub units) specify offsets for the |
| X coordinates of the right end of the line(s) in the frame border. |
| */ |
| void lclLinkRightEnd( |
| BorderEndResult& rResult, const Style& rBorder, |
| const DiagStyle& rRFromTL, const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, const DiagStyle& rRFromBL ) |
| { |
| /* Recycle lclLinkLeftEnd() function with mirrored vertical borders. */ |
| lclLinkLeftEnd( rResult, rBorder, rRFromTL.Mirror(), rRFromT.Mirror(), rRFromR, rRFromB.Mirror(), rRFromBL.Mirror() ); |
| rResult.Negate(); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // Linking of horizontal and vertical frame borders. |
| |
| /** Calculates X offsets for all line ends of a horizontal frame border. |
| |
| This function can be used for single and double frame borders. |
| See DrawHorFrameBorder() function for a description of all parameters. |
| |
| @param rResult |
| (out-param) The contained values (sub units) specify offsets for the |
| X coordinates of both ends of the line(s) in the frame border. To get |
| the actual X coordinates to draw the lines, these offsets have to be |
| added to the X coordinates of the reference points of the frame border |
| (the offsets may be negative). |
| */ |
| void lclLinkHorFrameBorder( |
| BorderResult& rResult, const Style& rBorder, |
| 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 ) |
| { |
| lclLinkLeftEnd( rResult.maBeg, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR ); |
| lclLinkRightEnd( rResult.maEnd, rBorder, rRFromTL, rRFromT, rRFromR, rRFromB, rRFromBL ); |
| } |
| |
| /** Calculates Y offsets for all line ends of a vertical frame border. |
| |
| This function can be used for single and double frame borders. |
| See DrawVerFrameBorder() function for a description of all parameters. |
| |
| @param rResult |
| (out-param) The contained values (sub units) specify offsets for the |
| Y coordinates of both ends of the line(s) in the frame border. To get |
| the actual Y coordinates to draw the lines, these offsets have to be |
| added to the Y coordinates of the reference points of the frame border |
| (the offsets may be negative). |
| */ |
| void lclLinkVerFrameBorder( |
| BorderResult& rResult, const Style& rBorder, |
| const DiagStyle& rTFromBL, const Style& rTFromL, const Style& rTFromT, const Style& rTFromR, const DiagStyle& rTFromBR, |
| const DiagStyle& rBFromTL, const Style& rBFromL, const Style& rBFromB, const Style& rBFromR, const DiagStyle& rBFromTR ) |
| { |
| /* Recycle lclLinkHorFrameBorder() function with correct parameters. The |
| frame border is virtually mirrored at the top-left to bottom-right |
| diagonal. rTFromBR and rBFromTL are mirrored to process their primary |
| and secondary lines correctly. */ |
| lclLinkHorFrameBorder( rResult, rBorder, |
| rTFromBL, rTFromL, rTFromT, rTFromR, rTFromBR.Mirror(), |
| rBFromTL.Mirror(), rBFromL, rBFromB, rBFromR, rBFromTR ); |
| } |
| |
| // ============================================================================ |
| |
| #if 0 |
| // Not used anymore, but not deleted for possible future usage. |
| |
| /** Returns the relative Y offset of the intercept point of 2 diagonal borders. |
| |
| @param nTLBROffs |
| Width offset (sub units) across the top-left to bottom-right frame border. |
| @param fTLBRAngle |
| Inner angle between horizontal and top-left to bottom-right frame border. |
| @param nBLTROffs |
| Width offset (sub units) across the bottom-left to top-right frame border. |
| @param fBLTRAngle |
| Inner angle between horizontal and bottom-left to top-right frame border. |
| @return |
| Offset (sub units) relative to the Y position of the centered intercept |
| point of both diagonal frame borders. |
| */ |
| long lclGetDiagDiagOffset( long nTLBROffs, double fTLBRAngle, long nBLTROffs, double fBLTRAngle ) |
| { |
| double fASin = sin( fTLBRAngle ); |
| double fACos = cos( fTLBRAngle ); |
| double fAX = -nTLBROffs * fASin; |
| double fAY = nTLBROffs * fACos; |
| double fRAX = fACos; |
| double fRAY = fASin; |
| |
| double fBSin = sin( fBLTRAngle ); |
| double fBCos = cos( fBLTRAngle ); |
| double fBX = nBLTROffs * fBSin; |
| double fBY = nBLTROffs * fBCos; |
| double fRBX = fBCos; |
| double fRBY = -fBSin; |
| |
| double fKA = (fRBX * (fBY - fAY) - fRBY * (fBX - fAX)) / (fRBX * fRAY - fRAX * fRBY); |
| return lclD2L( fAY + fKA * fRAY ); |
| } |
| #endif |
| |
| // ---------------------------------------------------------------------------- |
| // Linking of diagonal frame borders. |
| |
| /** Calculates clipping offsets for a top-left to bottom-right frame border. |
| |
| This function can be used for single and double frame borders. |
| See DrawDiagFrameBorders() function for a description of all parameters. |
| |
| @param rResult |
| (out-param) The contained values (sub units) specify offsets for all |
| borders of the reference rectangle containing the diagonal frame border. |
| */ |
| void lclLinkTLBRFrameBorder( |
| DiagBorderResult& rResult, const Style& rBorder, |
| const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL ) |
| { |
| bool bIsDbl = rBorder.Secn() != 0; |
| |
| rResult.maPrim.mnLClip = lclGetBehindEnd( rTLFromB ); |
| rResult.maPrim.mnRClip = (bIsDbl && rBRFromT.Secn()) ? lclGetEnd( rBRFromT ) : lclGetBeforeBeg( rBRFromT ); |
| rResult.maPrim.mnTClip = (bIsDbl && rTLFromR.Secn()) ? lclGetBeg( rTLFromR ) : lclGetBehindEnd( rTLFromR ); |
| rResult.maPrim.mnBClip = lclGetBeforeBeg( rBRFromL ); |
| |
| if( bIsDbl ) |
| { |
| rResult.maSecn.mnLClip = rTLFromB.Secn() ? lclGetBeg( rTLFromB ) : lclGetBehindEnd( rTLFromB ); |
| rResult.maSecn.mnRClip = lclGetBeforeBeg( rBRFromT ); |
| rResult.maSecn.mnTClip = lclGetBehindEnd( rTLFromR ); |
| rResult.maSecn.mnBClip = rBRFromL.Secn() ? lclGetEnd( rBRFromL ) : lclGetBeforeBeg( rBRFromL ); |
| } |
| } |
| |
| /** Calculates clipping offsets for a bottom-left to top-right frame border. |
| |
| This function can be used for single and double frame borders. |
| See DrawDiagFrameBorders() function for a description of all parameters. |
| |
| @param rResult |
| (out-param) The contained values (sub units) specify offsets for all |
| borders of the reference rectangle containing the diagonal frame border. |
| */ |
| void lclLinkBLTRFrameBorder( |
| DiagBorderResult& rResult, const Style& rBorder, |
| const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL ) |
| { |
| bool bIsDbl = rBorder.Secn() != 0; |
| |
| rResult.maPrim.mnLClip = lclGetBehindEnd( rBLFromT ); |
| rResult.maPrim.mnRClip = (bIsDbl && rTRFromB.Secn()) ? lclGetEnd( rTRFromB ) : lclGetBeforeBeg( rTRFromB ); |
| rResult.maPrim.mnTClip = lclGetBehindEnd( rTRFromL ); |
| rResult.maPrim.mnBClip = (bIsDbl && rBLFromR.Secn()) ? lclGetEnd( rBLFromR ) : lclGetBeforeBeg( rBLFromR ); |
| |
| if( bIsDbl ) |
| { |
| rResult.maSecn.mnLClip = rBLFromT.Secn() ? lclGetBeg( rBLFromT ) : lclGetBehindEnd( rBLFromT ); |
| rResult.maSecn.mnRClip = lclGetBeforeBeg( rTRFromB ); |
| rResult.maSecn.mnTClip = rTRFromL.Secn() ? lclGetBeg( rTRFromL ) : lclGetBehindEnd( rTRFromL ); |
| rResult.maSecn.mnBClip = lclGetBeforeBeg( rBLFromR ); |
| } |
| } |
| |
| /** Calculates clipping offsets for both diagonal frame borders. |
| |
| This function can be used for single and double frame borders. |
| See DrawDiagFrameBorders() function for a description of all parameters. |
| |
| @param rResult |
| (out-param) The contained values (sub units) specify offsets for all |
| borders of the reference rectangle containing the diagonal frame |
| borders. |
| */ |
| void lclLinkDiagFrameBorders( |
| DiagBordersResult& rResult, const Style& rTLBR, const Style& rBLTR, |
| const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL, |
| const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL ) |
| { |
| lclLinkTLBRFrameBorder( rResult.maTLBR, rTLBR, rTLFromB, rTLFromR, rBRFromT, rBRFromL ); |
| lclLinkBLTRFrameBorder( rResult.maBLTR, rBLTR, rBLFromT, rBLFromR, rTRFromB, rTRFromL ); |
| } |
| |
| // ============================================================================ |
| // Drawing functions |
| // ============================================================================ |
| |
| // ---------------------------------------------------------------------------- |
| // Simple helper functions |
| |
| /** Converts sub units to OutputDevice map units. */ |
| inline long lclToMapUnit( long nSubUnits ) |
| { |
| return ((nSubUnits < 0) ? (nSubUnits - 127) : (nSubUnits + 128)) / 256; |
| } |
| |
| /** Converts a point in sub units to an OutputDevice point. */ |
| inline Point lclToMapUnit( long nSubXPos, long nSubYPos ) |
| { |
| return Point( lclToMapUnit( nSubXPos ), lclToMapUnit( nSubYPos ) ); |
| } |
| |
| /** Returns a polygon constructed from a vector of points. */ |
| inline Polygon lclCreatePolygon( const PointVec& rPoints ) |
| { |
| return Polygon( static_cast< sal_uInt16 >( rPoints.size() ), &rPoints[ 0 ] ); |
| } |
| |
| /** Returns a polygon constructed from the four passed points. */ |
| Polygon lclCreatePolygon( const Point& rP1, const Point& rP2, const Point& rP3, const Point& rP4 ) |
| { |
| PointVec aPoints; |
| aPoints.reserve( 4 ); |
| aPoints.push_back( rP1 ); |
| aPoints.push_back( rP2 ); |
| aPoints.push_back( rP3 ); |
| aPoints.push_back( rP4 ); |
| return lclCreatePolygon( aPoints ); |
| } |
| |
| /** Returns a polygon constructed from the five passed points. */ |
| Polygon lclCreatePolygon( const Point& rP1, const Point& rP2, const Point& rP3, const Point& rP4, const Point& rP5 ) |
| { |
| PointVec aPoints; |
| aPoints.reserve( 5 ); |
| aPoints.push_back( rP1 ); |
| aPoints.push_back( rP2 ); |
| aPoints.push_back( rP3 ); |
| aPoints.push_back( rP4 ); |
| aPoints.push_back( rP5 ); |
| return lclCreatePolygon( aPoints ); |
| } |
| |
| /** Returns a polygon constructed from the two passed line positions. */ |
| inline Polygon lclCreatePolygon( const LinePoints& rPoints1, const LinePoints& rPoints2 ) |
| { |
| return lclCreatePolygon( rPoints1.maBeg, rPoints1.maEnd, rPoints2.maEnd, rPoints2.maBeg ); |
| } |
| |
| /** Sets the color of the passed frame style to the output device. |
| |
| Sets the line color and fill color in the output device. |
| |
| @param rDev |
| The output device the color has to be set to. The old colors are pushed |
| onto the device's stack and can be restored with a call to |
| OutputDevice::Pop(). Please take care about the correct calling order |
| of Pop() if this function is used with other functions pushing |
| something onto the stack. |
| @param rStyle |
| The border style that contains the line color to be set to the device. |
| */ |
| void lclSetColorToOutDev( OutputDevice& rDev, const Style& rStyle, const Color* pForceColor ) |
| { |
| rDev.Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); |
| rDev.SetLineColor( pForceColor ? *pForceColor : rStyle.GetColor() ); |
| rDev.SetFillColor( pForceColor ? *pForceColor : rStyle.GetColor() ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // Generic drawing functions. |
| |
| /** Draws a thin (1 pixel wide) line, optionally dotted, into the passed output device. */ |
| void lclDrawThinLine( OutputDevice& rDev, const Point& rBeg, const Point& rEnd, bool bDotted ) |
| { |
| #if SVX_FRAME_USE_LINEINFO |
| if( bDotted && (rBeg != rEnd) ) |
| { |
| // using LineInfo for dotted lines looks ugly and does not work well for diagonal lines |
| LineInfo aLineInfo( LINE_DASH, 1 ); |
| aLineInfo.SetDotCount( 1 ); |
| aLineInfo.SetDotLen( 1 ); |
| aLineInfo.SetDistance( 3 ); |
| rDev.DrawLine( rBeg, rEnd, aLineInfo ); |
| } |
| #else |
| Point aBeg( rDev.LogicToPixel( rBeg ) ); |
| Point aEnd( rDev.LogicToPixel( rEnd ) ); |
| if( bDotted && (aBeg != aEnd) ) |
| { |
| bool bHor = Abs( aEnd.X() - aBeg.X() ) > Abs( aEnd.Y() - aBeg.Y() ); |
| const Point& rBegPos( bHor ? ((aBeg.X() < aEnd.X()) ? aBeg : aEnd) : ((aBeg.Y() < aEnd.Y()) ? aBeg : aEnd ) ); |
| const Point& rEndPos( (rBegPos == aBeg) ? aEnd : aBeg ); |
| |
| long nAlongBeg = bHor ? rBegPos.X() : rBegPos.Y(); |
| long nAcrssBeg = bHor ? rBegPos.Y() : rBegPos.X(); |
| long nAlongSize = (bHor ? rEndPos.X() : rEndPos.Y()) - nAlongBeg; |
| long nAcrssSize = (bHor ? rEndPos.Y() : rEndPos.X()) - nAcrssBeg; |
| double fGradient = static_cast< double >( nAcrssSize ) / nAlongSize; |
| |
| PointVec aPoints; |
| aPoints.reserve( (nAlongSize + 1) / 2 ); |
| for( long nAlongIdx = 0; nAlongIdx <= nAlongSize; nAlongIdx += 2 ) |
| { |
| long nAl = nAlongBeg + nAlongIdx; |
| long nAc = nAcrssBeg + lclD2L( fGradient * nAlongIdx ); |
| aPoints.push_back( Point( bHor ? nAl : nAc, bHor ? nAc : nAl ) ); |
| } |
| |
| rDev.Push( PUSH_MAPMODE ); |
| rDev.SetMapMode( MAP_PIXEL ); |
| rDev.DrawPixel( lclCreatePolygon( aPoints ) ); |
| rDev.Pop(); // map mode |
| } |
| #endif |
| else |
| rDev.DrawLine( rBeg, rEnd ); |
| } |
| |
| /** Draws a thin (1 pixel wide) line, optionally dotted, into the passed output device. */ |
| inline void lclDrawThinLine( OutputDevice& rDev, const LinePoints& rPoints, bool bDotted ) |
| { |
| lclDrawThinLine( rDev, rPoints.maBeg, rPoints.maEnd, bDotted ); |
| } |
| |
| /** Draws a polygon with four points into the passed output device. */ |
| inline void lclDrawPolygon( OutputDevice& rDev, const Point& rP1, const Point& rP2, const Point& rP3, const Point& rP4 ) |
| { |
| rDev.DrawPolygon( lclCreatePolygon( rP1, rP2, rP3, rP4 ) ); |
| } |
| |
| /** Draws a polygon specified by two borders into the passed output device. */ |
| inline void lclDrawPolygon( OutputDevice& rDev, const LinePoints& rPoints1, const LinePoints& rPoints2 ) |
| { |
| rDev.DrawPolygon( lclCreatePolygon( rPoints1, rPoints2 ) ); |
| } |
| |
| // ============================================================================ |
| // Drawing of horizontal frame borders. |
| |
| /** Draws a horizontal thin or thick line into the passed output device. |
| |
| The X coordinates of the edges of the line are adjusted according to the |
| passed LineEndResult structs. A one pixel wide line can be drawn dotted. |
| */ |
| void lclDrawHorLine( |
| OutputDevice& rDev, |
| const Point& rLPos, const LineEndResult& rLRes, |
| const Point& rRPos, const LineEndResult& rRRes, |
| long nTOffs, long nBOffs, bool bDotted ) |
| { |
| LinePoints aTPoints( rLPos + lclToMapUnit( rLRes.mnOffs1, nTOffs ), rRPos + lclToMapUnit( rRRes.mnOffs1, nTOffs ) ); |
| if( nTOffs == nBOffs ) |
| lclDrawThinLine( rDev, aTPoints, bDotted ); |
| else |
| { |
| LinePoints aBPoints( rLPos + lclToMapUnit( rLRes.mnOffs2, nBOffs ), rRPos + lclToMapUnit( rRRes.mnOffs2, nBOffs ) ); |
| lclDrawPolygon( rDev, aTPoints, aBPoints ); |
| } |
| } |
| |
| /** Draws a horizontal frame border into the passed output device. |
| |
| @param rLPos |
| The top-left or bottom-left reference point of the diagonal frame border. |
| @param rRPos |
| The top-right or bottom-right reference point of the diagonal frame border. |
| @param rBorder |
| The frame style used to draw the border. |
| @param rResult |
| The X coordinates of the edges of all lines of the frame border are |
| adjusted according to the offsets contained here. |
| */ |
| void lclDrawHorFrameBorder( |
| OutputDevice& rDev, const Point& rLPos, const Point& rRPos, |
| const Style& rBorder, const BorderResult& rResult, const Color* pForceColor ) |
| { |
| DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawHorFrameBorder - line not visible" ); |
| DBG_ASSERT( rLPos.X() <= rRPos.X(), "svx::frame::lclDrawHorFrameBorder - wrong order of line ends" ); |
| DBG_ASSERT( rLPos.Y() == rRPos.Y(), "svx::frame::lclDrawHorFrameBorder - line not horizontal" ); |
| if( rLPos.X() <= rRPos.X() ) |
| { |
| lclSetColorToOutDev( rDev, rBorder, pForceColor ); |
| lclDrawHorLine( rDev, rLPos, rResult.maBeg.maPrim, rRPos, rResult.maEnd.maPrim, |
| lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Dotted() ); |
| if( rBorder.Secn() ) |
| lclDrawHorLine( rDev, rLPos, rResult.maBeg.maSecn, rRPos, rResult.maEnd.maSecn, |
| lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Dotted() ); |
| rDev.Pop(); // colors |
| } |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // Drawing of vertical frame borders. |
| |
| /** Draws a vertical thin or thick line into the passed output device. |
| |
| The Y coordinates of the edges of the line are adjusted according to the |
| passed LineEndResult structs. A one pixel wide line can be drawn dotted. |
| */ |
| void lclDrawVerLine( |
| OutputDevice& rDev, |
| const Point& rTPos, const LineEndResult& rTRes, |
| const Point& rBPos, const LineEndResult& rBRes, |
| long nLOffs, long nROffs, bool bDotted ) |
| { |
| LinePoints aLPoints( rTPos + lclToMapUnit( nLOffs, rTRes.mnOffs1 ), rBPos + lclToMapUnit( nLOffs, rBRes.mnOffs1 ) ); |
| if( nLOffs == nROffs ) |
| lclDrawThinLine( rDev, aLPoints, bDotted ); |
| else |
| { |
| LinePoints aRPoints( rTPos + lclToMapUnit( nROffs, rTRes.mnOffs2 ), rBPos + lclToMapUnit( nROffs, rBRes.mnOffs2 ) ); |
| lclDrawPolygon( rDev, aLPoints, aRPoints ); |
| } |
| } |
| |
| /** Draws a vertical frame border into the passed output device. |
| |
| @param rTPos |
| The top-left or top-right reference point of the diagonal frame border. |
| @param rBPos |
| The bottom-left or bottom-right reference point of the diagonal frame border. |
| @param rBorder |
| The frame style used to draw the border. |
| @param rResult |
| The Y coordinates of the edges of all lines of the frame border are |
| adjusted according to the offsets contained here. |
| */ |
| void lclDrawVerFrameBorder( |
| OutputDevice& rDev, const Point& rTPos, const Point& rBPos, |
| const Style& rBorder, const BorderResult& rResult, const Color* pForceColor ) |
| { |
| DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawVerFrameBorder - line not visible" ); |
| DBG_ASSERT( rTPos.Y() <= rBPos.Y(), "svx::frame::lclDrawVerFrameBorder - wrong order of line ends" ); |
| DBG_ASSERT( rTPos.X() == rBPos.X(), "svx::frame::lclDrawVerFrameBorder - line not vertical" ); |
| if( rTPos.Y() <= rBPos.Y() ) |
| { |
| lclSetColorToOutDev( rDev, rBorder, pForceColor ); |
| lclDrawVerLine( rDev, rTPos, rResult.maBeg.maPrim, rBPos, rResult.maEnd.maPrim, |
| lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Dotted() ); |
| if( rBorder.Secn() ) |
| lclDrawVerLine( rDev, rTPos, rResult.maBeg.maSecn, rBPos, rResult.maEnd.maSecn, |
| lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Dotted() ); |
| rDev.Pop(); // colors |
| } |
| } |
| |
| // ============================================================================ |
| // Drawing of diagonal frame borders, incudes clipping functions. |
| |
| /** Returns the drawing coordinates for a diagonal thin line. |
| |
| This function can be used for top-left to bottom-right and for bottom-left |
| to top-right lines. |
| |
| @param rRect |
| The reference rectangle of the diagonal frame border. |
| @param bTLBR |
| true = top-left to bottom-right; false = bottom-left to top-right. |
| @param nDiagOffs |
| Width offset (sub units) across the diagonal frame border. |
| @return |
| A struct containg start and end position of the diagonal line. |
| */ |
| LinePoints lclGetDiagLineEnds( const Rectangle& rRect, bool bTLBR, long nDiagOffs ) |
| { |
| LinePoints aPoints( rRect, bTLBR ); |
| bool bVert = rRect.GetWidth() < rRect.GetHeight(); |
| double fAngle = bVert ? GetVerDiagAngle( rRect ) : GetHorDiagAngle( rRect ); |
| // vertical top-left to bottom-right borders are handled mirrored |
| if( bVert && bTLBR ) |
| nDiagOffs = -nDiagOffs; |
| long nTOffs = bTLBR ? GetTLDiagOffset( 0, nDiagOffs, fAngle ) : GetTRDiagOffset( 0, nDiagOffs, fAngle ); |
| long nBOffs = bTLBR ? GetBRDiagOffset( 0, nDiagOffs, fAngle ) : GetBLDiagOffset( 0, nDiagOffs, fAngle ); |
| // vertical bottom-left to top-right borders are handled with exchanged end points |
| if( bVert && !bTLBR ) |
| std::swap( nTOffs, nBOffs ); |
| (bVert ? aPoints.maBeg.Y() : aPoints.maBeg.X()) += lclToMapUnit( nTOffs ); |
| (bVert ? aPoints.maEnd.Y() : aPoints.maEnd.X()) += lclToMapUnit( nBOffs ); |
| return aPoints; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // Clipping functions for diagonal frame borders. |
| |
| /** Limits the clipping region to the inner area of a rectange. |
| |
| Takes the values from the passed DiagLineResult struct into account. They |
| may specify to not clip one or more borders of a rectangle. |
| |
| @param rDev |
| The output device with the clipping region to be modified. The old |
| clipping region is pushed onto the device's stack and can be restored |
| with a call to OutputDevice::Pop(). Please take care about the correct |
| calling order of Pop() if this function is used with other functions |
| pushing something onto the stack. |
| @param rRect |
| The reference rectangle of the diagonal frame borders. |
| @param rResult |
| The result struct containing modifies for each border of the reference |
| rectangle. |
| */ |
| void lclPushDiagClipRect( OutputDevice& rDev, const Rectangle& rRect, const DiagLineResult& rResult ) |
| { |
| // PixelToLogic() regards internal offset of the output device |
| Rectangle aClipRect( rRect ); |
| aClipRect.Left() += lclToMapUnit( rResult.mnLClip ); |
| aClipRect.Top() += lclToMapUnit( rResult.mnTClip ); |
| aClipRect.Right() += lclToMapUnit( rResult.mnRClip ); |
| aClipRect.Bottom() += lclToMapUnit( rResult.mnBClip ); |
| // output device would adjust the rectangle -> invalidate it before |
| if( (aClipRect.GetWidth() < 1) ||(aClipRect.GetHeight() < 1) ) |
| aClipRect.SetEmpty(); |
| |
| rDev.Push( PUSH_CLIPREGION ); |
| rDev.IntersectClipRegion( aClipRect ); |
| } |
| |
| /** Excludes inner area of a crossing double frame border from clipping region. |
| |
| This function is used to modify the clipping region so that it excludes the |
| inner free area of a double diagonal frame border. This makes it possible |
| to draw a diagonal frame border in one step without taking care of the |
| crossing double frame border. |
| |
| @param rDev |
| The output device with the clipping region to be modified. The old |
| clipping region is pushed onto the device's stack and can be restored |
| with a call to OutputDevice::Pop(). Please take care about the correct |
| calling order of Pop() if this function is used with other functions |
| pushing something onto the stack. |
| @param rRect |
| The reference rectangle of the diagonal frame borders. |
| @param bTLBR |
| The orientation of the processed frame border (not the orientation of |
| the crossing frame border). |
| @param bCrossStyle |
| The style of the crossing frame border. Must be a double frame style. |
| */ |
| void lclPushCrossingClipRegion( OutputDevice& rDev, const Rectangle& rRect, bool bTLBR, const Style& rCrossStyle ) |
| { |
| DBG_ASSERT( rCrossStyle.Secn(), "lclGetCrossingClipRegion - use only for double styles" ); |
| LinePoints aLPoints( lclGetDiagLineEnds( rRect, !bTLBR, lclGetPrimEnd( rCrossStyle ) ) ); |
| LinePoints aRPoints( lclGetDiagLineEnds( rRect, !bTLBR, lclGetSecnBeg( rCrossStyle ) ) ); |
| |
| Region aClipReg; |
| if( bTLBR ) |
| { |
| aClipReg = lclCreatePolygon( |
| aLPoints.maBeg, aLPoints.maEnd, rRect.BottomRight(), rRect.BottomLeft(), rRect.TopLeft() ); |
| aClipReg.Union( lclCreatePolygon( |
| aRPoints.maBeg, aRPoints.maEnd, rRect.BottomRight(), rRect.TopRight(), rRect.TopLeft() ) ); |
| } |
| else |
| { |
| aClipReg = lclCreatePolygon( |
| aLPoints.maBeg, aLPoints.maEnd, rRect.BottomLeft(), rRect.TopLeft(), rRect.TopRight() ); |
| aClipReg.Union( lclCreatePolygon( |
| aRPoints.maBeg, aRPoints.maEnd, rRect.BottomLeft(), rRect.BottomRight(), rRect.TopRight() ) ); |
| } |
| |
| rDev.Push( PUSH_CLIPREGION ); |
| rDev.IntersectClipRegion( aClipReg ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| // Drawing functions for diagonal frame borders. |
| |
| /** Draws a diagonal thin or thick line into the passed output device. |
| |
| The clipping region of the output device is modified according to the |
| passed DiagLineResult struct. A one pixel wide line can be drawn dotted. |
| */ |
| void lclDrawDiagLine( |
| OutputDevice& rDev, const Rectangle& rRect, bool bTLBR, |
| const DiagLineResult& rResult, long nDiagOffs1, long nDiagOffs2, bool bDotted ) |
| { |
| lclPushDiagClipRect( rDev, rRect, rResult ); |
| LinePoints aLPoints( lclGetDiagLineEnds( rRect, bTLBR, nDiagOffs1 ) ); |
| if( nDiagOffs1 == nDiagOffs2 ) |
| lclDrawThinLine( rDev, aLPoints, bDotted ); |
| else |
| lclDrawPolygon( rDev, aLPoints, lclGetDiagLineEnds( rRect, bTLBR, nDiagOffs2 ) ); |
| rDev.Pop(); // clipping region |
| } |
| |
| /** Draws a diagonal frame border into the passed output device. |
| |
| The lines of the frame border are drawn interrupted, if the style of the |
| crossing frame border is double. |
| |
| @param rRect |
| The reference rectangle of the diagonal frame border. |
| @param bTLBR |
| The orientation of the diagonal frame border. |
| @param rBorder |
| The frame style used to draw the border. |
| @param rResult |
| Offsets (sub units) to modify the clipping region of the output device. |
| @param rCrossStyle |
| Style of the crossing diagonal frame border. |
| */ |
| void lclDrawDiagFrameBorder( |
| OutputDevice& rDev, const Rectangle& rRect, bool bTLBR, |
| const Style& rBorder, const DiagBorderResult& rResult, const Style& rCrossStyle, |
| const Color* pForceColor, bool bDiagDblClip ) |
| { |
| DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawDiagFrameBorder - line not visible" ); |
| |
| bool bClip = bDiagDblClip && rCrossStyle.Secn(); |
| if( bClip ) |
| lclPushCrossingClipRegion( rDev, rRect, bTLBR, rCrossStyle ); |
| |
| lclSetColorToOutDev( rDev, rBorder, pForceColor ); |
| lclDrawDiagLine( rDev, rRect, bTLBR, rResult.maPrim, lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Dotted() ); |
| if( rBorder.Secn() ) |
| lclDrawDiagLine( rDev, rRect, bTLBR, rResult.maSecn, lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Dotted() ); |
| rDev.Pop(); // colors |
| |
| if( bClip ) |
| rDev.Pop(); // clipping region |
| } |
| |
| /** Draws both diagonal frame borders into the passed output device. |
| |
| The lines of each frame border is drawn interrupted, if the style of the |
| other crossing frame border is double. |
| |
| @param rRect |
| The reference rectangle of the diagonal frame borders. |
| @param rTLBR |
| The frame style of the top-left to bottom-right frame border. |
| @param rBLTR |
| The frame style of the bottom-left to top-right frame border. |
| @param rResult |
| Offsets (sub units) to modify the clipping region of the output device. |
| */ |
| void lclDrawDiagFrameBorders( |
| OutputDevice& rDev, const Rectangle& rRect, |
| const Style& rTLBR, const Style& rBLTR, const DiagBordersResult& rResult, |
| const Color* pForceColor, bool bDiagDblClip ) |
| { |
| DBG_ASSERT( (rRect.GetWidth() > 1) && (rRect.GetHeight() > 1), "svx::frame::lclDrawDiagFrameBorders - rectangle too small" ); |
| if( (rRect.GetWidth() > 1) && (rRect.GetHeight() > 1) ) |
| { |
| bool bDrawTLBR = rTLBR.Prim() != 0; |
| bool bDrawBLTR = rBLTR.Prim() != 0; |
| bool bFirstDrawBLTR = rTLBR.Secn() != 0; |
| |
| if( bDrawBLTR && bFirstDrawBLTR ) |
| lclDrawDiagFrameBorder( rDev, rRect, false, rBLTR, rResult.maBLTR, rTLBR, pForceColor, bDiagDblClip ); |
| if( bDrawTLBR ) |
| lclDrawDiagFrameBorder( rDev, rRect, true, rTLBR, rResult.maTLBR, rBLTR, pForceColor, bDiagDblClip ); |
| if( bDrawBLTR && !bFirstDrawBLTR ) |
| lclDrawDiagFrameBorder( rDev, rRect, false, rBLTR, rResult.maBLTR, rTLBR, pForceColor, bDiagDblClip ); |
| } |
| } |
| |
| // ============================================================================ |
| |
| } // namespace |
| |
| // ============================================================================ |
| // Classes |
| // ============================================================================ |
| |
| #define SCALEVALUE( value ) lclScaleValue( value, fScale, nMaxWidth ) |
| |
| void Style::Clear() |
| { |
| Set( Color(), 0, 0, 0 ); |
| } |
| |
| void Style::Set( sal_uInt16 nP, sal_uInt16 nD, sal_uInt16 nS ) |
| { |
| /* nP nD nS -> mnPrim mnDist mnSecn |
| -------------------------------------- |
| any any 0 nP 0 0 |
| 0 any >0 nS 0 0 |
| >0 0 >0 nP 0 0 |
| >0 >0 >0 nP nD nS |
| */ |
| mnPrim = nP ? nP : nS; |
| mnDist = (nP && nS) ? nD : 0; |
| mnSecn = (nP && nD) ? nS : 0; |
| } |
| |
| void Style::Set( const Color& rColor, sal_uInt16 nP, sal_uInt16 nD, sal_uInt16 nS ) |
| { |
| maColor = rColor; |
| Set( nP, nD, nS ); |
| } |
| |
| void Style::Set( const SvxBorderLine& rBorder, double fScale, sal_uInt16 nMaxWidth, bool bUseDots ) |
| { |
| maColor = rBorder.GetColor(); |
| |
| sal_uInt16 nPrim = rBorder.GetOutWidth(); |
| sal_uInt16 nDist = rBorder.GetDistance(); |
| sal_uInt16 nSecn = rBorder.GetInWidth(); |
| |
| if( !nSecn ) // no or single frame border |
| { |
| Set( SCALEVALUE( nPrim ), 0, 0 ); |
| mbDotted = bUseDots && (0 < nPrim) && (nPrim < 10); |
| } |
| else |
| { |
| Set( SCALEVALUE( nPrim ), SCALEVALUE( nDist ), SCALEVALUE( nSecn ) ); |
| mbDotted = false; |
| // Enlarge the style if distance is too small due to rounding losses. |
| sal_uInt16 nPixWidth = SCALEVALUE( nPrim + nDist + nSecn ); |
| if( nPixWidth > GetWidth() ) |
| mnDist = nPixWidth - mnPrim - mnSecn; |
| // Shrink the style if it is too thick for the control. |
| while( GetWidth() > nMaxWidth ) |
| { |
| // First decrease space between lines. |
| if( mnDist ) |
| --mnDist; |
| // Still too thick? Decrease the line widths. |
| if( GetWidth() > nMaxWidth ) |
| { |
| if( mnPrim && (mnPrim == mnSecn) ) |
| { |
| // Both lines equal - decrease both to keep symmetry. |
| --mnPrim; |
| --mnSecn; |
| } |
| else |
| { |
| // Decrease each line for itself |
| if( mnPrim ) |
| --mnPrim; |
| if( (GetWidth() > nMaxWidth) && mnSecn ) |
| --mnSecn; |
| } |
| } |
| } |
| } |
| } |
| |
| void Style::Set( const SvxBorderLine* pBorder, double fScale, sal_uInt16 nMaxWidth, bool bUseDots ) |
| { |
| if( pBorder ) |
| Set( *pBorder, fScale, nMaxWidth, bUseDots ); |
| else |
| { |
| Clear(); |
| mbDotted = false; |
| } |
| } |
| |
| Style& Style::ScaleSelf( double fScale, sal_uInt16 nMaxWidth ) |
| { |
| Set( SCALEVALUE( mnPrim ), SCALEVALUE( mnDist ), SCALEVALUE( mnSecn ) ); |
| return *this; |
| } |
| |
| Style Style::Scale( double fScale, sal_uInt16 nMaxWidth ) const |
| { |
| return Style( *this ).ScaleSelf( fScale, nMaxWidth ); |
| } |
| |
| Style& Style::MirrorSelf() |
| { |
| if( mnSecn ) |
| std::swap( mnPrim, mnSecn ); |
| if( meRefMode != REFMODE_CENTERED ) |
| meRefMode = (meRefMode == REFMODE_BEGIN) ? REFMODE_END : REFMODE_BEGIN; |
| return *this; |
| } |
| |
| Style Style::Mirror() const |
| { |
| return Style( *this ).MirrorSelf(); |
| } |
| |
| bool operator==( const Style& rL, const Style& rR ) |
| { |
| return (rL.Prim() == rR.Prim()) && (rL.Dist() == rR.Dist()) && (rL.Secn() == rR.Secn()) && |
| (rL.GetColor() == rR.GetColor()) && (rL.GetRefMode() == rR.GetRefMode()) && (rL.Dotted() == rR.Dotted()); |
| } |
| |
| bool operator<( const Style& rL, const Style& rR ) |
| { |
| // different total widths -> rL<rR, if rL is thinner |
| sal_uInt16 nLW = rL.GetWidth(); |
| sal_uInt16 nRW = rR.GetWidth(); |
| if( nLW != nRW ) return nLW < nRW; |
| |
| // one line double, the other single -> rL<rR, if rL is single |
| if( (rL.Secn() == 0) != (rR.Secn() == 0) ) return rL.Secn() == 0; |
| |
| // both lines double with different distances -> rL<rR, if distance of rL greater |
| if( (rL.Secn() && rR.Secn()) && (rL.Dist() != rR.Dist()) ) return rL.Dist() > rR.Dist(); |
| |
| // both lines single and 1 unit thick, only one is dotted -> rL<rR, if rL is dotted |
| if( (nLW == 1) && (rL.Dotted() != rR.Dotted()) ) return rL.Dotted(); |
| |
| // seem to be equal |
| return false; |
| } |
| |
| #undef SCALEVALUE |
| |
| // ============================================================================ |
| // Various helper functions |
| // ============================================================================ |
| |
| double GetHorDiagAngle( long nWidth, long nHeight ) |
| { |
| return atan2( static_cast< double >( Abs( nHeight ) ), static_cast< double >( Abs( nWidth ) ) ); |
| } |
| |
| // ============================================================================ |
| |
| long GetTLDiagOffset( long nVerOffs, long nDiagOffs, double fAngle ) |
| { |
| return lclD2L( nVerOffs / tan( fAngle ) + nDiagOffs / sin( fAngle ) ); |
| } |
| |
| long GetBLDiagOffset( long nVerOffs, long nDiagOffs, double fAngle ) |
| { |
| return lclD2L( -nVerOffs / tan( fAngle ) + nDiagOffs / sin( fAngle ) ); |
| } |
| |
| long GetBRDiagOffset( long nVerOffs, long nDiagOffs, double fAngle ) |
| { |
| return -lclD2L( -nVerOffs / tan( fAngle ) - nDiagOffs / sin( fAngle ) ); |
| } |
| |
| long GetTRDiagOffset( long nVerOffs, long nDiagOffs, double fAngle ) |
| { |
| return -lclD2L( nVerOffs / tan( fAngle ) - nDiagOffs / sin( fAngle ) ); |
| } |
| |
| // ============================================================================ |
| |
| bool CheckFrameBorderConnectable( const Style& rLBorder, const Style& rRBorder, |
| const Style& rTFromTL, const Style& rTFromT, const Style& rTFromTR, |
| const Style& rBFromBL, const Style& rBFromB, const Style& rBFromBR ) |
| { |
| return // returns 1 AND (2a OR 2b) |
| // 1) only, if both frame borders are equal |
| (rLBorder == rRBorder) |
| && |
| ( |
| ( |
| // 2a) if the borders are not double, at least one of the vertical must not be double |
| !rLBorder.Secn() && (!rTFromT.Secn() || !rBFromB.Secn()) |
| ) |
| || |
| ( |
| // 2b) if the borders are double, all other borders must not be double |
| rLBorder.Secn() && |
| !rTFromTL.Secn() && !rTFromT.Secn() && !rTFromTR.Secn() && |
| !rBFromBL.Secn() && !rBFromB.Secn() && !rBFromBR.Secn() |
| ) |
| ); |
| } |
| |
| // ============================================================================ |
| // Drawing functions |
| // ============================================================================ |
| |
| void DrawHorFrameBorder( OutputDevice& rDev, |
| 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& rRFromTL, const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, const DiagStyle& rRFromBL, |
| const Color* pForceColor ) |
| { |
| if( rBorder.Prim() ) |
| { |
| BorderResult aResult; |
| lclLinkHorFrameBorder( aResult, rBorder, |
| rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR, |
| rRFromTL, rRFromT, rRFromR, rRFromB, rRFromBL ); |
| lclDrawHorFrameBorder( rDev, rLPos, rRPos, rBorder, aResult, pForceColor ); |
| } |
| } |
| |
| void DrawHorFrameBorder( OutputDevice& rDev, |
| const Point& rLPos, const Point& rRPos, const Style& rBorder, |
| const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, |
| const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, |
| const Color* pForceColor ) |
| { |
| /* Recycle complex version of the DrawHorFrameBorder() function with empty diagonals. */ |
| const DiagStyle aNoStyle; |
| DrawHorFrameBorder( |
| rDev, rLPos, rRPos, rBorder, |
| aNoStyle, rLFromT, rLFromL, rLFromB, aNoStyle, |
| aNoStyle, rRFromT, rRFromR, rRFromB, aNoStyle, |
| pForceColor ); |
| } |
| |
| void DrawHorFrameBorder( OutputDevice& rDev, |
| const Point& rLPos, const Point& rRPos, const Style& rBorder, const Color* pForceColor ) |
| { |
| if( rBorder.Prim() ) |
| lclDrawHorFrameBorder( rDev, rLPos, rRPos, rBorder, BorderResult(), pForceColor ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| void DrawVerFrameBorder( OutputDevice& rDev, |
| const Point& rTPos, const Point& rBPos, const Style& rBorder, |
| const DiagStyle& rTFromBL, const Style& rTFromL, const Style& rTFromT, const Style& rTFromR, const DiagStyle& rTFromBR, |
| const DiagStyle& rBFromTL, const Style& rBFromL, const Style& rBFromB, const Style& rBFromR, const DiagStyle& rBFromTR, |
| const Color* pForceColor ) |
| { |
| if( rBorder.Prim() ) |
| { |
| BorderResult aResult; |
| lclLinkVerFrameBorder( aResult, rBorder, |
| rTFromBL, rTFromL, rTFromT, rTFromR, rTFromBR, |
| rBFromTL, rBFromL, rBFromB, rBFromR, rBFromTR ); |
| lclDrawVerFrameBorder( rDev, rTPos, rBPos, rBorder, aResult, pForceColor ); |
| } |
| } |
| |
| void DrawVerFrameBorder( OutputDevice& rDev, |
| const Point& rTPos, const Point& rBPos, const Style& rBorder, |
| const Style& rTFromL, const Style& rTFromT, const Style& rTFromR, |
| const Style& rBFromL, const Style& rBFromB, const Style& rBFromR, |
| const Color* pForceColor ) |
| { |
| /* Recycle complex version of the DrawVerFrameBorder() function with empty diagonals. */ |
| const DiagStyle aNoStyle; |
| DrawVerFrameBorder( |
| rDev, rTPos, rBPos, rBorder, |
| aNoStyle, rTFromL, rTFromT, rTFromR, aNoStyle, |
| aNoStyle, rBFromL, rBFromB, rBFromR, aNoStyle, |
| pForceColor ); |
| } |
| |
| void DrawVerFrameBorder( OutputDevice& rDev, |
| const Point& rTPos, const Point& rBPos, const Style& rBorder, const Color* pForceColor ) |
| { |
| if( rBorder.Prim() ) |
| lclDrawVerFrameBorder( rDev, rTPos, rBPos, rBorder, BorderResult(), pForceColor ); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| void DrawVerFrameBorderSlanted( OutputDevice& rDev, |
| const Point& rTPos, const Point& rBPos, const Style& rBorder, const Color* pForceColor ) |
| { |
| DBG_ASSERT( rTPos.Y() < rBPos.Y(), "svx::frame::DrawVerFrameBorderSlanted - wrong order of line ends" ); |
| if( rBorder.Prim() && (rTPos.Y() < rBPos.Y()) ) |
| { |
| if( rTPos.X() == rBPos.X() ) |
| { |
| DrawVerFrameBorder( rDev, rTPos, rBPos, rBorder, pForceColor ); |
| } |
| else |
| { |
| const LineEndResult aRes; |
| |
| Style aScaled( rBorder ); |
| aScaled.ScaleSelf( 1.0 / cos( GetVerDiagAngle( rTPos, rBPos ) ) ); |
| |
| lclSetColorToOutDev( rDev, aScaled, pForceColor ); |
| lclDrawVerLine( rDev, rTPos, aRes, rBPos, aRes, |
| lclGetBeg( aScaled ), lclGetPrimEnd( aScaled ), aScaled.Dotted() ); |
| if( aScaled.Secn() ) |
| lclDrawVerLine( rDev, rTPos, aRes, rBPos, aRes, |
| lclGetSecnBeg( aScaled ), lclGetEnd( aScaled ), aScaled.Dotted() ); |
| rDev.Pop(); // colors |
| } |
| } |
| } |
| |
| // ============================================================================ |
| |
| void DrawDiagFrameBorders( |
| OutputDevice& rDev, const Rectangle& rRect, const Style& rTLBR, const Style& rBLTR, |
| const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL, |
| const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL, |
| const Color* pForceColor, bool bDiagDblClip ) |
| { |
| if( rTLBR.Prim() || rBLTR.Prim() ) |
| { |
| DiagBordersResult aResult; |
| lclLinkDiagFrameBorders( aResult, rTLBR, rBLTR, |
| rTLFromB, rTLFromR, rBRFromT, rBRFromL, rBLFromT, rBLFromR, rTRFromB, rTRFromL ); |
| lclDrawDiagFrameBorders( rDev, rRect, rTLBR, rBLTR, aResult, pForceColor, bDiagDblClip ); |
| } |
| } |
| |
| // ============================================================================ |
| |
| } // namespace frame |
| } // namespace svx |
| |