1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svx.hxx"
26 #include <svx/sdr/overlay/overlayselection.hxx>
27 #include <basegfx/polygon/b2dpolygontools.hxx>
28 #include <basegfx/polygon/b2dpolygon.hxx>
29 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
30 #include <svtools/optionsdrawinglayer.hxx>
31 #include <vcl/svapp.hxx>
32 #include <vcl/outdev.hxx>
33 #include <drawinglayer/primitive2d/invertprimitive2d.hxx>
34 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
35 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
36 #include <svx/sdr/overlay/overlaymanager.hxx>
37 
38 //////////////////////////////////////////////////////////////////////////////
39 
40 namespace sdr
41 {
42 	namespace overlay
43 	{
44         // combine rages geometrically to a single, ORed polygon
impCombineRangesToPolyPolygon(const std::vector<basegfx::B2DRange> & rRanges)45 		basegfx::B2DPolyPolygon impCombineRangesToPolyPolygon(const std::vector< basegfx::B2DRange >& rRanges)
46 		{
47             const sal_uInt32 nCount(rRanges.size());
48 			basegfx::B2DPolyPolygon aRetval;
49 
50 			for(sal_uInt32 a(0); a < nCount; a++)
51             {
52 				const basegfx::B2DPolygon aDiscretePolygon(basegfx::tools::createPolygonFromRect(rRanges[a]));
53 
54 				if(0 == a)
55 				{
56 					aRetval.append(aDiscretePolygon);
57 				}
58 				else
59 				{
60 					aRetval = basegfx::tools::solvePolygonOperationOr(aRetval, basegfx::B2DPolyPolygon(aDiscretePolygon));
61 				}
62 			}
63 
64 			return aRetval;
65 		}
66 
67 		// check if wanted type OVERLAY_TRANSPARENT or OVERLAY_SOLID
68 		// is possible. If not, fallback to invert mode (classic mode)
impCheckPossibleOverlayType(OverlayType aOverlayType)69     	OverlayType impCheckPossibleOverlayType(OverlayType aOverlayType)
70         {
71 			if(OVERLAY_INVERT != aOverlayType)
72 			{
73 				const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
74 
75 				if(!aSvtOptionsDrawinglayer.IsTransparentSelection())
76 				{
77 					// not possible when switched off by user
78 					return OVERLAY_INVERT;
79 				}
80 				else
81 				{
82 					const OutputDevice *pOut = Application::GetDefaultDevice();
83 
84 					if(pOut->GetSettings().GetStyleSettings().GetHighContrastMode())
85 					{
86 						// not possible when in high contrast mode
87 						return  OVERLAY_INVERT;
88 					}
89 
90 					if(!pOut->supportsOperation(OutDevSupport_TransparentRect))
91 					{
92 						// not possible when no fast transparence paint is supported on the system
93 						return OVERLAY_INVERT;
94 					}
95 				}
96 			}
97 
98             return aOverlayType;
99         }
100 
createOverlayObjectPrimitive2DSequence()101         drawinglayer::primitive2d::Primitive2DSequence OverlaySelection::createOverlayObjectPrimitive2DSequence()
102 		{
103 			drawinglayer::primitive2d::Primitive2DSequence aRetval;
104 			const sal_uInt32 nCount(getRanges().size());
105 
106 			if(nCount)
107 			{
108 				// create range primitives
109                 const bool bInvert(OVERLAY_INVERT == maLastOverlayType);
110 			    basegfx::BColor aRGBColor(getBaseColor().getBColor());
111                 aRetval.realloc(nCount);
112 
113                 if(bInvert)
114                 {
115                     // force color to white for invert to get a full invert
116                     aRGBColor = basegfx::BColor(1.0, 1.0, 1.0);
117                 }
118 
119 				for(sal_uInt32 a(0);a < nCount; a++)
120 				{
121 					const basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(maRanges[a]));
122 					aRetval[a] = drawinglayer::primitive2d::Primitive2DReference(
123 						new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
124 							basegfx::B2DPolyPolygon(aPolygon),
125 							aRGBColor));
126 				}
127 
128 				if(bInvert)
129 				{
130 					// embed all in invert primitive
131 					const drawinglayer::primitive2d::Primitive2DReference aInvert(
132 						new drawinglayer::primitive2d::InvertPrimitive2D(
133 							aRetval));
134 					aRetval = drawinglayer::primitive2d::Primitive2DSequence(&aInvert, 1);
135 				}
136                 else if(OVERLAY_TRANSPARENT == maLastOverlayType)
137                 {
138 			        // embed all rectangles in transparent paint
139 					const double fTransparence(mnLastTransparence / 100.0);
140 					const drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparence(
141 				        new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
142 					        aRetval,
143 					        fTransparence));
144 
145                     if(getBorder())
146                     {
147 					    const basegfx::B2DPolyPolygon aPolyPolygon(impCombineRangesToPolyPolygon(getRanges()));
148 			            const drawinglayer::primitive2d::Primitive2DReference aSelectionOutline(
149 				            new drawinglayer::primitive2d::PolyPolygonHairlinePrimitive2D(
150 					            aPolyPolygon,
151 					            aRGBColor));
152 
153                         // add both to result
154                         aRetval.realloc(2);
155                         aRetval[0] = aUnifiedTransparence;
156                         aRetval[1] = aSelectionOutline;
157                     }
158                     else
159                     {
160                         // just add transparent part
161     					aRetval = drawinglayer::primitive2d::Primitive2DSequence(&aUnifiedTransparence, 1);
162                     }
163                 }
164 			}
165 
166 			return aRetval;
167 		}
168 
OverlaySelection(OverlayType eType,const Color & rColor,const std::vector<basegfx::B2DRange> & rRanges,bool bBorder)169 		OverlaySelection::OverlaySelection(
170 			OverlayType eType,
171 			const Color& rColor,
172 			const std::vector< basegfx::B2DRange >& rRanges,
173             bool bBorder)
174 		:	OverlayObject(rColor),
175             meOverlayType(eType),
176             maRanges(rRanges),
177             maLastOverlayType(eType),
178             mnLastTransparence(0),
179             mbBorder(bBorder)
180 		{
181             // no AA for selection overlays
182             allowAntiAliase(false);
183 		}
184 
~OverlaySelection()185 		OverlaySelection::~OverlaySelection()
186 		{
187 			if(getOverlayManager())
188 			{
189 				getOverlayManager()->remove(*this);
190 			}
191 		}
192 
getOverlayObjectPrimitive2DSequence() const193 		drawinglayer::primitive2d::Primitive2DSequence OverlaySelection::getOverlayObjectPrimitive2DSequence() const
194         {
195             // get current values
196            	const OverlayType aNewOverlayType(impCheckPossibleOverlayType(meOverlayType));
197 			const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
198 			const sal_uInt16 nNewTransparence(aSvtOptionsDrawinglayer.GetTransparentSelectionPercent());
199 
200 			if(getPrimitive2DSequence().hasElements())
201 			{
202                 if(aNewOverlayType != maLastOverlayType
203                     || nNewTransparence != mnLastTransparence)
204                 {
205                     // conditions of last local decomposition have changed, delete
206 				    const_cast< OverlaySelection* >(this)->setPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DSequence());
207                 }
208 			}
209 
210 			if(!getPrimitive2DSequence().hasElements())
211 			{
212 				// remember new values
213 				const_cast< OverlaySelection* >(this)->maLastOverlayType = aNewOverlayType;
214 				const_cast< OverlaySelection* >(this)->mnLastTransparence = nNewTransparence;
215 			}
216 
217 			// call base implementation
218 			return OverlayObject::getOverlayObjectPrimitive2DSequence();
219         }
220 
setRanges(const std::vector<basegfx::B2DRange> & rNew)221 		void OverlaySelection::setRanges(const std::vector< basegfx::B2DRange >& rNew)
222 		{
223 			if(rNew != maRanges)
224 			{
225 				maRanges = rNew;
226 				objectChange();
227 			}
228 		}
229 	} // end of namespace overlay
230 } // end of namespace sdr
231 
232 //////////////////////////////////////////////////////////////////////////////
233 // eof
234