1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_xmloff.hxx"
30 #include <tools/debug.hxx>
31 #include <com/sun/star/io/XOutputStream.hpp>
32 #include <xmloff/xmltkmap.hxx>
33 #include <xmloff/xmluconv.hxx>
34 #include "xmloff/xmlnmspe.hxx"
35 #include <xmloff/xmltoken.hxx>
36 #include <xmloff/xmlimp.hxx>
37 #include <xmloff/nmspmap.hxx>
38 #include <xmloff/XMLBase64ImportContext.hxx>
39 #include "XMLBackgroundImageContext.hxx"
40 
41 using ::rtl::OUString;
42 using ::rtl::OUStringBuffer;
43 
44 using namespace ::com::sun::star;
45 using namespace ::com::sun::star::uno;
46 using namespace ::com::sun::star::style;
47 using namespace ::com::sun::star::io;
48 using namespace ::xmloff::token;
49 
50 enum SvXMLTokenMapAttrs
51 {
52 	XML_TOK_BGIMG_HREF,
53 	XML_TOK_BGIMG_TYPE,
54 	XML_TOK_BGIMG_ACTUATE,
55 	XML_TOK_BGIMG_SHOW,
56 	XML_TOK_BGIMG_POSITION,
57 	XML_TOK_BGIMG_REPEAT,
58 	XML_TOK_BGIMG_FILTER,
59     XML_TOK_BGIMG_OPACITY,
60 	XML_TOK_NGIMG_END=XML_TOK_UNKNOWN
61 };
62 const SvXMLTokenMapEntry* lcl_getBGImgAttributesAttrTokenMap()
63 {
64     static __FAR_DATA SvXMLTokenMapEntry aBGImgAttributesAttrTokenMap[] =
65     {
66 	    { XML_NAMESPACE_XLINK, XML_HREF, 		XML_TOK_BGIMG_HREF		},
67 	    { XML_NAMESPACE_XLINK, XML_TYPE, 		XML_TOK_BGIMG_TYPE		},
68 	    { XML_NAMESPACE_XLINK, XML_ACTUATE,	    XML_TOK_BGIMG_ACTUATE	},
69 	    { XML_NAMESPACE_XLINK, XML_SHOW, 		XML_TOK_BGIMG_SHOW 		},
70 	    { XML_NAMESPACE_STYLE, XML_POSITION, 	XML_TOK_BGIMG_POSITION	},
71 	    { XML_NAMESPACE_STYLE, XML_REPEAT, 	    XML_TOK_BGIMG_REPEAT	},
72 	    { XML_NAMESPACE_STYLE, XML_FILTER_NAME, XML_TOK_BGIMG_FILTER	},
73         { XML_NAMESPACE_DRAW,  XML_OPACITY,		XML_TOK_BGIMG_OPACITY	},
74 	    XML_TOKEN_MAP_END
75     };
76     return aBGImgAttributesAttrTokenMap;
77 }
78 
79 
80 
81 SvXMLEnumMapEntry psXML_BrushHoriPos[] =
82 {
83 	{ XML_LEFT, 		GraphicLocation_LEFT_MIDDLE	},
84 	{ XML_RIGHT,		GraphicLocation_RIGHT_MIDDLE	},
85 	{ XML_TOKEN_INVALID,					0			}
86 };
87 
88 SvXMLEnumMapEntry psXML_BrushVertPos[] =
89 {
90 	{ XML_TOP,			GraphicLocation_MIDDLE_TOP	},
91 	{ XML_BOTTOM,		GraphicLocation_MIDDLE_BOTTOM	},
92 	{ XML_TOKEN_INVALID,					0			}
93 };
94 
95 void lcl_xmlbic_MergeHoriPos( GraphicLocation& ePos,
96 								   GraphicLocation eHori )
97 {
98 	DBG_ASSERT( GraphicLocation_LEFT_MIDDLE==eHori ||
99 				GraphicLocation_MIDDLE_MIDDLE==eHori ||
100 				GraphicLocation_RIGHT_MIDDLE==eHori,
101 				"lcl_xmlbic_MergeHoriPos: vertical pos must be middle" );
102 
103 	switch( ePos )
104 	{
105 	case GraphicLocation_LEFT_TOP:
106 	case GraphicLocation_MIDDLE_TOP:
107 	case GraphicLocation_RIGHT_TOP:
108 		ePos = GraphicLocation_LEFT_MIDDLE==eHori
109 				? GraphicLocation_LEFT_TOP
110 				: (GraphicLocation_MIDDLE_MIDDLE==eHori
111 						? GraphicLocation_MIDDLE_TOP
112 						: GraphicLocation_RIGHT_TOP);
113 		break;
114 
115 	case GraphicLocation_LEFT_MIDDLE:
116 	case GraphicLocation_MIDDLE_MIDDLE:
117 	case GraphicLocation_RIGHT_MIDDLE:
118 		ePos = eHori;
119 		break;
120 
121 	case GraphicLocation_LEFT_BOTTOM:
122 	case GraphicLocation_MIDDLE_BOTTOM:
123 	case GraphicLocation_RIGHT_BOTTOM:
124 		ePos = GraphicLocation_LEFT_MIDDLE==eHori
125 				? GraphicLocation_LEFT_BOTTOM
126 				: (GraphicLocation_MIDDLE_MIDDLE==eHori
127 						? GraphicLocation_MIDDLE_BOTTOM
128 						: GraphicLocation_RIGHT_BOTTOM);
129 		break;
130 	default:
131 		break;
132 	}
133 }
134 
135 void lcl_xmlbic_MergeVertPos( GraphicLocation& ePos,
136 							  	   			  GraphicLocation eVert )
137 {
138 	DBG_ASSERT( GraphicLocation_MIDDLE_TOP==eVert ||
139 				GraphicLocation_MIDDLE_MIDDLE==eVert ||
140 				GraphicLocation_MIDDLE_BOTTOM==eVert,
141 				"lcl_xmlbic_MergeVertPos: horizontal pos must be middle" );
142 
143 	switch( ePos )
144 	{
145 	case GraphicLocation_LEFT_TOP:
146 	case GraphicLocation_LEFT_MIDDLE:
147 	case GraphicLocation_LEFT_BOTTOM:
148 		ePos = GraphicLocation_MIDDLE_TOP==eVert
149 				? GraphicLocation_LEFT_TOP
150 				: (GraphicLocation_MIDDLE_MIDDLE==eVert
151 						? GraphicLocation_LEFT_MIDDLE
152 						: GraphicLocation_LEFT_BOTTOM);
153 		ePos = eVert;
154 		break;
155 
156 	case GraphicLocation_MIDDLE_TOP:
157 	case GraphicLocation_MIDDLE_MIDDLE:
158 	case GraphicLocation_MIDDLE_BOTTOM:
159 		ePos = eVert;
160 		break;
161 
162 	case GraphicLocation_RIGHT_TOP:
163 	case GraphicLocation_RIGHT_MIDDLE:
164 	case GraphicLocation_RIGHT_BOTTOM:
165 		ePos = GraphicLocation_MIDDLE_TOP==eVert
166 				? GraphicLocation_RIGHT_TOP
167 				: (GraphicLocation_MIDDLE_MIDDLE==eVert
168 						? GraphicLocation_RIGHT_MIDDLE
169 						: GraphicLocation_RIGHT_BOTTOM);
170 		break;
171 	default:
172 		break;
173 	}
174 }
175 
176 TYPEINIT1( XMLBackgroundImageContext, XMLElementPropertyContext );
177 
178 void XMLBackgroundImageContext::ProcessAttrs(
179 		const Reference< xml::sax::XAttributeList >& xAttrList )
180 {
181 	SvXMLTokenMap aTokenMap( lcl_getBGImgAttributesAttrTokenMap() );
182 
183 	ePos = GraphicLocation_NONE;
184 
185 	sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
186 	for( sal_Int16 i=0; i < nAttrCount; i++ )
187 	{
188 		const OUString& rAttrName = xAttrList->getNameByIndex( i );
189 		OUString aLocalName;
190 		sal_uInt16 nPrefix =
191 			GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
192 															&aLocalName );
193 		const OUString& rValue = xAttrList->getValueByIndex( i );
194 
195 		switch( aTokenMap.Get( nPrefix, aLocalName ) )
196 		{
197 		case XML_TOK_BGIMG_HREF:
198 			sURL = rValue;
199 			if( GraphicLocation_NONE == ePos )
200 				ePos = GraphicLocation_TILED;
201 			break;
202 		case XML_TOK_BGIMG_TYPE:
203 		case XML_TOK_BGIMG_ACTUATE:
204 		case XML_TOK_BGIMG_SHOW:
205 			break;
206 		case XML_TOK_BGIMG_POSITION:
207 			{
208 				GraphicLocation eNewPos = GraphicLocation_NONE, eTmp;
209 				sal_uInt16 nTmp;
210 				SvXMLTokenEnumerator aTokenEnum( rValue );
211 				OUString aToken;
212 				sal_Bool bHori = sal_False, bVert = sal_False;
213 				sal_Bool bOK = sal_True;
214 				while( bOK && aTokenEnum.getNextToken( aToken ) )
215 				{
216 					if( bHori && bVert )
217 					{
218 						bOK = sal_False;
219 					}
220 					else if( -1 != aToken.indexOf( sal_Unicode('%') ) )
221 					{
222 						sal_Int32 nPrc = 50;
223 						if( SvXMLUnitConverter::convertPercent( nPrc, aToken ) )
224 						{
225 							if( !bHori )
226 							{
227 								eNewPos = nPrc < 25
228 									? GraphicLocation_LEFT_TOP
229 									: (nPrc < 75 ? GraphicLocation_MIDDLE_MIDDLE
230 												: GraphicLocation_RIGHT_BOTTOM);
231 								bHori = sal_True;
232 							}
233 							else
234 							{
235 								eTmp = nPrc < 25
236 									? GraphicLocation_LEFT_TOP
237 									: (nPrc < 75 ? GraphicLocation_LEFT_MIDDLE
238 											     : GraphicLocation_LEFT_BOTTOM);
239 								lcl_xmlbic_MergeVertPos( eNewPos, eTmp );
240 								bVert = sal_True;
241 							}
242 						}
243 						else
244 						{
245 							// wrong percentage
246 							bOK = sal_False;
247 						}
248 					}
249 					else if( IsXMLToken( aToken, XML_CENTER ) )
250 					{
251 						if( bHori )
252 							lcl_xmlbic_MergeVertPos( eNewPos,
253 										  GraphicLocation_MIDDLE_MIDDLE );
254 						else if ( bVert )
255 							lcl_xmlbic_MergeHoriPos( eNewPos,
256 										  GraphicLocation_MIDDLE_MIDDLE );
257 						else
258 							eNewPos = GraphicLocation_MIDDLE_MIDDLE;
259 					}
260 					else if( SvXMLUnitConverter::convertEnum( nTmp, aToken,
261 														 psXML_BrushHoriPos ) )
262 					{
263 						if( bVert )
264 							lcl_xmlbic_MergeHoriPos( eNewPos,
265 										(GraphicLocation)nTmp );
266 						else if( !bHori )
267 							eNewPos = (GraphicLocation)nTmp;
268 						else
269 							bOK = sal_False;
270 						bHori = sal_True;
271 					}
272 					else if( SvXMLUnitConverter::convertEnum( nTmp, aToken,
273 														 psXML_BrushVertPos ) )
274 					{
275 						if( bHori )
276 							lcl_xmlbic_MergeVertPos( eNewPos,
277 											(GraphicLocation)nTmp );
278 						else if( !bVert )
279 							eNewPos = (GraphicLocation)nTmp;
280 						else
281 							bOK = sal_False;
282 						bVert = sal_True;
283 					}
284 					else
285 					{
286 						bOK = sal_False;
287 					}
288 				}
289 
290 				bOK &= GraphicLocation_NONE != eNewPos;
291 				if( bOK )
292 					ePos = eNewPos;
293 			}
294 			break;
295 		case XML_TOK_BGIMG_REPEAT:
296 			{
297 				sal_uInt16 nPos = GraphicLocation_NONE;
298                 static SvXMLEnumMapEntry psXML_BrushRepeat[] =
299                 {
300 	                { XML_BACKGROUND_REPEAT,		GraphicLocation_TILED	},
301 	                { XML_BACKGROUND_NO_REPEAT, 	GraphicLocation_MIDDLE_MIDDLE		},
302 	                { XML_BACKGROUND_STRETCH,		GraphicLocation_AREA	},
303 	                { XML_TOKEN_INVALID,			0			}
304                 };
305 				if( SvXMLUnitConverter::convertEnum( nPos, rValue,
306 												psXML_BrushRepeat ) )
307 				{
308 					if( GraphicLocation_MIDDLE_MIDDLE != nPos ||
309 						GraphicLocation_NONE == ePos ||
310 						GraphicLocation_AREA == ePos ||
311 						GraphicLocation_TILED == ePos )
312 						ePos = (GraphicLocation)nPos;
313 				}
314 			}
315 			break;
316 		case XML_TOK_BGIMG_FILTER:
317 			sFilter = rValue;
318 			break;
319         case XML_TOK_BGIMG_OPACITY:
320             {
321                 sal_Int32 nTmp;
322                 // convert from percent and clip
323                 if( SvXMLUnitConverter::convertPercent( nTmp, rValue ) )
324                 {
325                     if( (nTmp >= 0) && (nTmp <= 100) )
326                         nTransparency = static_cast<sal_Int8>( 100-nTmp );
327                 }
328             }
329             break;
330 		}
331 	}
332 
333 }
334 
335 XMLBackgroundImageContext::XMLBackgroundImageContext(
336 		SvXMLImport& rImport, sal_uInt16 nPrfx,
337 		const OUString& rLName,
338 		const Reference< xml::sax::XAttributeList > & xAttrList,
339 		const XMLPropertyState& rProp,
340 		sal_Int32 nPosIdx,
341 		sal_Int32 nFilterIdx,
342         sal_Int32 nTransparencyIdx,
343 		::std::vector< XMLPropertyState > &rProps ) :
344 	XMLElementPropertyContext( rImport, nPrfx, rLName, rProp, rProps ),
345 	aPosProp( nPosIdx ),
346 	aFilterProp( nFilterIdx ),
347     aTransparencyProp( nTransparencyIdx ),
348     nTransparency( 0 )
349 {
350 	ProcessAttrs( xAttrList );
351 }
352 
353 XMLBackgroundImageContext::~XMLBackgroundImageContext()
354 {
355 }
356 
357 SvXMLImportContext *XMLBackgroundImageContext::CreateChildContext(
358 		sal_uInt16 nPrefix, const OUString& rLocalName,
359 		const Reference< xml::sax::XAttributeList > & xAttrList )
360 {
361 	SvXMLImportContext *pContext = NULL;
362 	if( (XML_NAMESPACE_OFFICE == nPrefix) &&
363 		xmloff::token::IsXMLToken( rLocalName,
364 										xmloff::token::XML_BINARY_DATA ) )
365 	{
366 		if( !sURL.getLength() && !xBase64Stream.is() )
367 		{
368 			xBase64Stream = GetImport().GetStreamForGraphicObjectURLFromBase64();
369 			if( xBase64Stream.is() )
370 				pContext = new XMLBase64ImportContext( GetImport(), nPrefix,
371 													rLocalName, xAttrList,
372 													xBase64Stream );
373 		}
374 	}
375 	if( !pContext )
376 	{
377 		pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
378 	}
379 
380 	return pContext;
381 }
382 
383 void XMLBackgroundImageContext::EndElement()
384 {
385 	if( sURL.getLength() )
386 	{
387 		sURL = GetImport().ResolveGraphicObjectURL( sURL, sal_False );
388 	}
389 	else if( xBase64Stream.is() )
390 	{
391 		sURL = GetImport().ResolveGraphicObjectURLFromBase64( xBase64Stream );
392 		xBase64Stream = 0;
393 	}
394 
395 	if( !sURL.getLength() )
396 		ePos = GraphicLocation_NONE;
397 	else if( GraphicLocation_NONE == ePos )
398 		ePos = GraphicLocation_TILED;
399 
400 	aProp.maValue <<= sURL;
401 	aPosProp.maValue <<= ePos;
402 	aFilterProp.maValue <<= sFilter;
403     aTransparencyProp.maValue <<= nTransparency;
404 
405 	SetInsert( sal_True );
406 	XMLElementPropertyContext::EndElement();
407 
408 	if( -1 != aPosProp.mnIndex )
409 		rProperties.push_back( aPosProp );
410 	if( -1 != aFilterProp.mnIndex )
411 		rProperties.push_back( aFilterProp );
412 	if( -1 != aTransparencyProp.mnIndex )
413 		rProperties.push_back( aTransparencyProp );
414 }
415