Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <ctype.h>
21 : #include <stdlib.h>
22 : #include <stdio.h>
23 : #include <limits.h>
24 : #include <rtl/ustrbuf.hxx>
25 : #include <vcl/svapp.hxx>
26 : #include <svtools/htmltokn.h>
27 : #include <comphelper/string.hxx>
28 : #include "css1kywd.hxx"
29 : #include "parcss1.hxx"
30 :
31 : // Loop-Check: Um Endlos-Schleifen zu vermeiden, wird in jeder
32 : // Schalife geprueft, ob ein Fortschritt in der Eingabe-Position
33 : // stattgefunden hat
34 : #define LOOP_CHECK
35 :
36 : #ifdef LOOP_CHECK
37 :
38 : #define LOOP_CHECK_DECL \
39 : sal_Int32 nOldInPos = SAL_MAX_INT32;
40 : #define LOOP_CHECK_RESTART \
41 : nOldInPos = SAL_MAX_INT32;
42 : #define LOOP_CHECK_CHECK( where ) \
43 : OSL_ENSURE( nOldInPos!=nInPos || cNextCh==(sal_Unicode)EOF, where ); \
44 : if( nOldInPos==nInPos && cNextCh!=(sal_Unicode)EOF ) \
45 : break; \
46 : else \
47 : nOldInPos = nInPos;
48 :
49 : #else
50 :
51 : #define LOOP_CHECK_DECL
52 : #define LOOP_CHECK_RESTART
53 : #define LOOP_CHECK_CHECK( where )
54 :
55 : #endif
56 :
57 : const sal_Int32 MAX_LEN = 1024;
58 :
59 1100 : void CSS1Parser::InitRead( const OUString& rIn )
60 : {
61 1100 : nlLineNr = 0;
62 1100 : nlLinePos = 0;
63 :
64 1100 : bWhiteSpace = true; // Wenn noch nichts gelesen wurde ist das wie WS
65 1100 : bEOF = false;
66 1100 : eState = CSS1_PAR_WORKING;
67 1100 : nValue = 0.;
68 :
69 1100 : aIn = rIn;
70 1100 : nInPos = 0;
71 1100 : cNextCh = GetNextChar();
72 1100 : nToken = GetNextToken();
73 1100 : }
74 :
75 129598 : sal_Unicode CSS1Parser::GetNextChar()
76 : {
77 129598 : if( nInPos >= aIn.getLength() )
78 : {
79 1100 : bEOF = true;
80 1100 : return (sal_Unicode)EOF;
81 : }
82 :
83 128498 : sal_Unicode c = aIn[nInPos];
84 128498 : nInPos++;
85 :
86 128498 : if( c == '\n' )
87 : {
88 38 : IncLineNr();
89 38 : SetLinePos( 1L );
90 : }
91 : else
92 128460 : IncLinePos();
93 :
94 128498 : return c;
95 : }
96 :
97 : // Diese Funktion realisiert den in
98 :
99 : // http://www.w3.orh/pub/WWW/TR/WD-css1.html
100 : // bzw. http://www.w3.orh/pub/WWW/TR/WD-css1-960220.html
101 :
102 : // beschriebenen Scanner fuer CSS1. Es handelt sich um eine direkte
103 : // Umsetzung der dort beschriebenen Lex-Grammatik
104 :
105 23650 : CSS1Token CSS1Parser::GetNextToken()
106 : {
107 23650 : CSS1Token nRet = CSS1_NULL;
108 23650 : aToken = "";
109 :
110 35678 : do {
111 : // Merken, ob davor White-Space gelesen wurde
112 35678 : bool bPrevWhiteSpace = bWhiteSpace;
113 35678 : bWhiteSpace = false;
114 :
115 35678 : bool bNextCh = true;
116 35678 : switch( cNextCh )
117 : {
118 : case '/': // COMMENT | '/'
119 : {
120 0 : cNextCh = GetNextChar();
121 0 : if( '*' == cNextCh )
122 : {
123 : // COMMENT
124 0 : cNextCh = GetNextChar();
125 :
126 0 : bool bAsterisk = false;
127 0 : while( !(bAsterisk && '/'==cNextCh) && !IsEOF() )
128 : {
129 0 : bAsterisk = ('*'==cNextCh);
130 0 : cNextCh = GetNextChar();
131 : }
132 : }
133 : else
134 : {
135 : // '/'
136 0 : bNextCh = false;
137 0 : nRet = CSS1_SLASH;
138 : }
139 : }
140 0 : break;
141 :
142 : case '@': // '@import' | '@XXX'
143 : {
144 10 : cNextCh = GetNextChar();
145 10 : if (comphelper::string::isalphaAscii(cNextCh))
146 : {
147 : // den naechsten Identifer scannen
148 10 : OUStringBuffer sTmpBuffer( 32L );
149 40 : do {
150 40 : sTmpBuffer.append( cNextCh );
151 40 : cNextCh = GetNextChar();
152 50 : } while( (comphelper::string::isalnumAscii(cNextCh) ||
153 70 : '-' == cNextCh) && !IsEOF() );
154 :
155 10 : aToken += sTmpBuffer.makeStringAndClear();
156 :
157 : // und schauen, ob wir ihn kennen
158 10 : switch( aToken[0] )
159 : {
160 : case 'i':
161 : case 'I':
162 0 : if( aToken.equalsIgnoreAsciiCase( "import" ) )
163 0 : nRet = CSS1_IMPORT_SYM;
164 0 : break;
165 : // /Feature: PrintExt
166 : case 'p':
167 : case 'P':
168 10 : if( aToken.equalsIgnoreAsciiCase( "page" ) )
169 10 : nRet = CSS1_PAGE_SYM;
170 10 : break;
171 : // /Feature: PrintExt
172 : }
173 :
174 : // Fehlerbehandlung: '@ident' und alles bis
175 : // zu einem Semikolon der dem Ende des folgenden
176 : // Blocks ignorieren
177 10 : if( CSS1_NULL==nRet )
178 : {
179 0 : aToken = "";
180 0 : sal_uInt16 nBlockLvl = 0;
181 0 : sal_Unicode cQuoteCh = 0;
182 0 : bool bDone = false, bEscape = false;
183 0 : while( !bDone && !IsEOF() )
184 : {
185 0 : bool bOldEscape = bEscape;
186 0 : bEscape = false;
187 0 : switch( cNextCh )
188 : {
189 : case '{':
190 0 : if( !cQuoteCh && !bOldEscape )
191 0 : nBlockLvl++;
192 0 : break;
193 : case ';':
194 0 : if( !cQuoteCh && !bOldEscape )
195 0 : bDone = nBlockLvl==0;
196 0 : break;
197 : case '}':
198 0 : if( !cQuoteCh && !bOldEscape )
199 0 : bDone = --nBlockLvl==0;
200 0 : break;
201 : case '\"':
202 : case '\'':
203 0 : if( !bOldEscape )
204 : {
205 0 : if( cQuoteCh )
206 : {
207 0 : if( cQuoteCh == cNextCh )
208 0 : cQuoteCh = 0;
209 : }
210 : else
211 : {
212 0 : cQuoteCh = cNextCh;
213 : }
214 : }
215 0 : break;
216 : case '\\':
217 0 : if( !bOldEscape )
218 0 : bEscape = true;
219 0 : break;
220 : }
221 0 : cNextCh = GetNextChar();
222 : }
223 : }
224 :
225 10 : bNextCh = false;
226 : }
227 : }
228 10 : break;
229 :
230 : case '!': // '!' 'legal' | '!' 'important' | syntax error
231 : {
232 : // White Space ueberlesen
233 0 : cNextCh = GetNextChar();
234 0 : while( ( ' ' == cNextCh ||
235 0 : (cNextCh >= 0x09 && cNextCh <= 0x0d) ) && !IsEOF() )
236 : {
237 0 : bWhiteSpace = true;
238 0 : cNextCh = GetNextChar();
239 : }
240 :
241 0 : if( 'i'==cNextCh || 'I'==cNextCh)
242 : {
243 : // den naechsten Identifer scannen
244 0 : OUStringBuffer sTmpBuffer( 32L );
245 0 : do {
246 0 : sTmpBuffer.append( cNextCh );
247 0 : cNextCh = GetNextChar();
248 0 : } while( (comphelper::string::isalnumAscii(cNextCh) ||
249 0 : '-' == cNextCh) && !IsEOF() );
250 :
251 0 : aToken += sTmpBuffer.makeStringAndClear();
252 :
253 0 : if( ( 'i'==aToken[0] || 'I'==aToken[0] ) &&
254 0 : aToken.equalsIgnoreAsciiCase( "important" ) )
255 : {
256 : // '!' 'important'
257 0 : nRet = CSS1_IMPORTANT_SYM;
258 : }
259 : else
260 : {
261 : // Fehlerbehandlung: '!' ignorieren, IDENT nicht
262 0 : nRet = CSS1_IDENT;
263 : }
264 :
265 0 : bWhiteSpace = false;
266 0 : bNextCh = false;
267 : }
268 : else
269 : {
270 : // Fehlerbehandlung: '!' ignorieren
271 0 : bNextCh = false;
272 : }
273 : }
274 0 : break;
275 :
276 : case '\"':
277 : case '\'': // STRING
278 : {
279 : // \... geht noch nicht!!!
280 2 : sal_Unicode cQuoteChar = cNextCh;
281 2 : cNextCh = GetNextChar();
282 :
283 2 : OUStringBuffer sTmpBuffer( MAX_LEN );
284 32 : do {
285 32 : sTmpBuffer.append( cNextCh );
286 32 : cNextCh = GetNextChar();
287 32 : } while( cQuoteChar != cNextCh && !IsEOF() );
288 :
289 2 : aToken += sTmpBuffer.toString();
290 :
291 2 : nRet = CSS1_STRING;
292 : }
293 2 : break;
294 :
295 : case '0':
296 : case '1':
297 : case '2':
298 : case '3':
299 : case '4':
300 : case '5':
301 : case '6':
302 : case '7':
303 : case '8':
304 : case '9': // NUMBER | PERCENTAGE | LENGTH
305 : {
306 : // die aktuelle Position retten
307 5310 : sal_Size nInPosSave = nInPos;
308 5310 : sal_Unicode cNextChSave = cNextCh;
309 5310 : sal_uInt32 nlLineNrSave = nlLineNr;
310 5310 : sal_uInt32 nlLinePosSave = nlLinePos;
311 5310 : bool bEOFSave = bEOF;
312 :
313 : // erstmal versuchen eine Hex-Zahl zu scannen
314 5310 : OUStringBuffer sTmpBuffer( 16 );
315 5374 : do {
316 5374 : sTmpBuffer.append( cNextCh );
317 5374 : cNextCh = GetNextChar();
318 10748 : } while( sTmpBuffer.getLength() < 7 &&
319 11850 : ( ('0'<=cNextCh && '9'>=cNextCh) ||
320 11742 : ('A'<=cNextCh && 'F'>=cNextCh) ||
321 11856 : ('a'<=cNextCh && 'f'>=cNextCh) ) &&
322 64 : !IsEOF() );
323 :
324 5310 : if( sTmpBuffer.getLength()==6 )
325 : {
326 : // wir haben eine hexadezimale Farbe gefunden
327 0 : aToken += sTmpBuffer.makeStringAndClear();
328 0 : nRet = CSS1_HEXCOLOR;
329 0 : bNextCh = false;
330 :
331 0 : break;
332 : }
333 :
334 : // sonst versuchen wir es mit einer Zahl
335 5310 : nInPos = nInPosSave;
336 5310 : cNextCh = cNextChSave;
337 5310 : nlLineNr = nlLineNrSave;
338 5310 : nlLinePos = nlLinePosSave;
339 5310 : bEOF = bEOFSave;
340 :
341 : // erstmal die Zahl scannen
342 5310 : sTmpBuffer.setLength( 0L );
343 17984 : do {
344 17984 : sTmpBuffer.append( cNextCh );
345 17984 : cNextCh = GetNextChar();
346 30658 : } while( (('0'<=cNextCh && '9'>=cNextCh) || '.'==cNextCh) &&
347 12674 : !IsEOF() );
348 :
349 5310 : aToken += sTmpBuffer.makeStringAndClear();
350 5310 : nValue = aToken.toDouble();
351 :
352 : // White Space ueberlesen
353 21244 : while( ( ' ' == cNextCh ||
354 10622 : (cNextCh >= 0x09 && cNextCh <= 0x0d) ) && !IsEOF() )
355 : {
356 2 : bWhiteSpace = true;
357 2 : cNextCh = GetNextChar();
358 : }
359 :
360 : // und nun Schauen, ob es eine Einheit gibt
361 5310 : switch( cNextCh )
362 : {
363 : case '%': // PERCENTAGE
364 4 : bWhiteSpace = false;
365 4 : nRet = CSS1_PERCENTAGE;
366 4 : break;
367 :
368 : case 'c':
369 : case 'C': // LENGTH cm | LENGTH IDENT
370 : case 'e':
371 : case 'E': // LENGTH (em | ex) | LENGTH IDENT
372 : case 'i':
373 : case 'I': // LENGTH inch | LENGTH IDENT
374 : case 'p':
375 : case 'P': // LENGTH (pt | px | pc) | LENGTH IDENT
376 : case 'm':
377 : case 'M': // LENGTH mm | LENGTH IDENT
378 : {
379 : // die aktuelle Position retten
380 5296 : sal_Int32 nInPosOld = nInPos;
381 5296 : sal_Unicode cNextChOld = cNextCh;
382 5296 : sal_uLong nlLineNrOld = nlLineNr;
383 5296 : sal_uLong nlLinePosOld = nlLinePos;
384 5296 : bool bEOFOld = bEOF;
385 :
386 : // den naechsten Identifer scannen
387 5296 : OUString aIdent;
388 10592 : OUStringBuffer sTmpBuffer2( 64L );
389 10592 : do {
390 10592 : sTmpBuffer2.append( cNextCh );
391 10592 : cNextCh = GetNextChar();
392 15888 : } while( (comphelper::string::isalnumAscii(cNextCh) ||
393 15888 : '-' == cNextCh) && !IsEOF() );
394 :
395 5296 : aIdent += sTmpBuffer2.makeStringAndClear();
396 :
397 : // Ist es eine Einheit?
398 5296 : const sal_Char *pCmp1 = 0, *pCmp2 = 0, *pCmp3 = 0;
399 5296 : double nScale1 = 1., nScale2 = 1.;
400 5296 : CSS1Token nToken1 = CSS1_LENGTH,
401 5296 : nToken2 = CSS1_LENGTH,
402 5296 : nToken3 = CSS1_LENGTH;
403 5296 : switch( aIdent[0] )
404 : {
405 : case 'c':
406 : case 'C':
407 42 : pCmp1 = "cm";
408 42 : nScale1 = (72.*20.)/2.54; // twip
409 42 : break;
410 : case 'e':
411 : case 'E':
412 0 : pCmp1 = "em";
413 0 : nToken1 = CSS1_EMS;
414 :
415 0 : pCmp2 = "ex";
416 0 : nToken2 = CSS1_EMX;
417 0 : break;
418 : case 'i':
419 : case 'I':
420 4184 : pCmp1 = "in";
421 4184 : nScale1 = 72.*20.; // twip
422 4184 : break;
423 : case 'm':
424 : case 'M':
425 0 : pCmp1 = "mm";
426 0 : nScale1 = (72.*20.)/25.4; // twip
427 0 : break;
428 : case 'p':
429 : case 'P':
430 1070 : pCmp1 = "pt";
431 1070 : nScale1 = 20.; // twip
432 :
433 1070 : pCmp2 = "pc";
434 1070 : nScale2 = 12.*20.; // twip
435 :
436 1070 : pCmp3 = "px";
437 1070 : nToken3 = CSS1_PIXLENGTH;
438 1070 : break;
439 : }
440 :
441 5296 : double nScale = 0.0;
442 : OSL_ENSURE( pCmp1, "Wo kommt das erste Zeichen her?" );
443 5296 : if( aIdent.equalsIgnoreAsciiCaseAscii( pCmp1 ) )
444 : {
445 4250 : nScale = nScale1;
446 4250 : nRet = nToken1;
447 : }
448 2092 : else if( pCmp2 &&
449 1046 : aIdent.equalsIgnoreAsciiCaseAscii( pCmp2 ) )
450 : {
451 0 : nScale = nScale2;
452 0 : nRet = nToken2;
453 : }
454 2092 : else if( pCmp3 &&
455 1046 : aIdent.equalsIgnoreAsciiCaseAscii( pCmp3 ) )
456 : {
457 1046 : nScale = 1.; // nScale3
458 1046 : nRet = nToken3;
459 : }
460 : else
461 : {
462 0 : nRet = CSS1_NUMBER;
463 : }
464 :
465 5296 : if( CSS1_LENGTH==nRet && nScale!=1.0 )
466 4250 : nValue *= nScale;
467 :
468 5296 : if( nRet == CSS1_NUMBER )
469 : {
470 0 : nInPos = nInPosOld;
471 0 : cNextCh = cNextChOld;
472 0 : nlLineNr = nlLineNrOld;
473 0 : nlLinePos = nlLinePosOld;
474 0 : bEOF = bEOFOld;
475 : }
476 : else
477 : {
478 5296 : bWhiteSpace = false;
479 : }
480 10592 : bNextCh = false;
481 : }
482 5296 : break;
483 : default: // NUMBER IDENT
484 10 : bNextCh = false;
485 10 : nRet = CSS1_NUMBER;
486 10 : break;
487 5310 : }
488 : }
489 5310 : break;
490 :
491 : case ':': // ':'
492 : // link/visited/active abfangen !!!
493 5362 : nRet = CSS1_COLON;
494 5362 : break;
495 :
496 : case '.': // DOT_W_WS | DOT_WO_WS
497 12 : nRet = bPrevWhiteSpace ? CSS1_DOT_W_WS : CSS1_DOT_WO_WS;
498 12 : break;
499 :
500 : case '+': // '+'
501 0 : nRet = CSS1_PLUS;
502 0 : break;
503 :
504 : case '-': // '-'
505 2 : nRet = CSS1_MINUS;
506 2 : break;
507 :
508 : case '{': // '{'
509 30 : nRet = CSS1_OBRACE;
510 30 : break;
511 :
512 : case '}': // '}'
513 30 : nRet = CSS1_CBRACE;
514 30 : break;
515 :
516 : case ';': // ';'
517 4250 : nRet = CSS1_SEMICOLON;
518 4250 : break;
519 :
520 : case ',': // ','
521 0 : nRet = CSS1_COMMA;
522 0 : break;
523 :
524 : case '#': // '#'
525 1052 : cNextCh = GetNextChar();
526 1056 : if( ('0'<=cNextCh && '9'>=cNextCh) ||
527 8 : ('a'<=cNextCh && 'f'>=cNextCh) ||
528 0 : ('A'<=cNextCh && 'F'>=cNextCh) )
529 : {
530 : // die aktuelle Position retten
531 1052 : sal_Int32 nInPosSave = nInPos;
532 1052 : sal_Unicode cNextChSave = cNextCh;
533 1052 : sal_uLong nlLineNrSave = nlLineNr;
534 1052 : sal_uLong nlLinePosSave = nlLinePos;
535 1052 : bool bEOFSave = bEOF;
536 :
537 : // erstmal versuchen eine Hex-Zahl zu scannen
538 1052 : OUStringBuffer sTmpBuffer( 6L );
539 6312 : do {
540 6312 : sTmpBuffer.append( cNextCh );
541 6312 : cNextCh = GetNextChar();
542 12624 : } while( sTmpBuffer.getLength() < 7 &&
543 13688 : ( ('0'<=cNextCh && '9'>=cNextCh) ||
544 2152 : ('A'<=cNextCh && 'F'>=cNextCh) ||
545 12656 : ('a'<=cNextCh && 'f'>=cNextCh) ) &&
546 5260 : !IsEOF() );
547 :
548 1052 : if( sTmpBuffer.getLength()==6 || sTmpBuffer.getLength()==3 )
549 : {
550 : // wir haben eine hexadezimale Farbe gefunden
551 1052 : aToken += sTmpBuffer.makeStringAndClear();
552 1052 : nRet = CSS1_HEXCOLOR;
553 1052 : bNextCh = false;
554 :
555 1052 : break;
556 : }
557 :
558 : // sonst versuchen wir es mit einer Zahl
559 0 : nInPos = nInPosSave;
560 0 : cNextCh = cNextChSave;
561 0 : nlLineNr = nlLineNrSave;
562 0 : nlLinePos = nlLinePosSave;
563 0 : bEOF = bEOFSave;
564 : }
565 :
566 0 : nRet = CSS1_HASH;
567 0 : bNextCh = false;
568 0 : break;
569 :
570 : case ' ':
571 : case '\t':
572 : case '\r':
573 : case '\n': // White-Space
574 12028 : bWhiteSpace = true;
575 12028 : break;
576 :
577 : case (sal_Unicode)EOF:
578 1100 : if( IsEOF() )
579 : {
580 1100 : eState = CSS1_PAR_ACCEPTED;
581 1100 : bNextCh = false;
582 1100 : break;
583 : }
584 : // no break
585 :
586 : default: // IDENT | syntax error
587 6490 : if (comphelper::string::isalphaAscii(cNextCh))
588 : {
589 : // IDENT
590 :
591 6490 : bool bHexColor = true;
592 :
593 : // den naechsten Identifer scannen
594 6490 : OUStringBuffer sTmpBuffer( 64L );
595 65378 : do {
596 65378 : sTmpBuffer.append( cNextCh );
597 65378 : if( bHexColor )
598 : {
599 16402 : bHexColor = sTmpBuffer.getLength()<7 &&
600 22884 : ( ('0'<=cNextCh && '9'>=cNextCh) ||
601 22882 : ('A'<=cNextCh && 'F'>=cNextCh) ||
602 22880 : ('a'<=cNextCh && 'f'>=cNextCh) );
603 : }
604 65378 : cNextCh = GetNextChar();
605 76158 : } while( (comphelper::string::isalnumAscii(cNextCh) ||
606 124266 : '-' == cNextCh) && !IsEOF() );
607 :
608 6490 : aToken += sTmpBuffer.makeStringAndClear();
609 :
610 6490 : if( bHexColor && sTmpBuffer.getLength()==6 )
611 : {
612 0 : bNextCh = false;
613 0 : nRet = CSS1_HEXCOLOR;
614 :
615 0 : break;
616 : }
617 6490 : if( '('==cNextCh &&
618 0 : ( (('u'==aToken[0] || 'U'==aToken[0]) &&
619 0 : aToken.equalsIgnoreAsciiCase( "url" )) ||
620 0 : (('r'==aToken[0] || 'R'==aToken[0]) &&
621 0 : aToken.equalsIgnoreAsciiCase( "rgb" )) ) )
622 : {
623 0 : sal_uInt16 nNestCnt = 0;
624 0 : OUStringBuffer sTmpBuffer2( 64L );
625 0 : do {
626 0 : sTmpBuffer2.append( cNextCh );
627 0 : switch( cNextCh )
628 : {
629 0 : case '(': nNestCnt++; break;
630 0 : case ')': nNestCnt--; break;
631 : }
632 0 : cNextCh = GetNextChar();
633 0 : } while( (nNestCnt>1 || ')'!=cNextCh) && !IsEOF() );
634 0 : sTmpBuffer2.append( cNextCh );
635 0 : aToken += sTmpBuffer2.makeStringAndClear();
636 0 : bNextCh = true;
637 0 : nRet = 'u'==aToken[0] || 'U'==aToken[0]
638 : ? CSS1_URL
639 0 : : CSS1_RGB;
640 : }
641 : else
642 : {
643 6490 : bNextCh = false;
644 6490 : nRet = CSS1_IDENT;
645 6490 : }
646 : }
647 : // Fehlerbehandlung: Zeichen ignorieren
648 6490 : break;
649 : }
650 35678 : if( bNextCh )
651 21720 : cNextCh = GetNextChar();
652 :
653 35678 : } while( CSS1_NULL==nRet && IsParserWorking() );
654 :
655 23650 : return nRet;
656 : }
657 :
658 : // Dies folegenden Funktionen realisieren den in
659 :
660 : // http://www.w3.orh/pub/WWW/TR/WD-css1.html
661 : // bzw. http://www.w3.orh/pub/WWW/TR/WD-css1-960220.html
662 :
663 : // beschriebenen Parser fuer CSS1. Es handelt sich um eine direkte
664 : // Umsetzung der dort beschriebenen Grammatik
665 :
666 : // stylesheet
667 : // : import* rule*
668 :
669 : // import
670 : // : IMPORT_SYM url
671 :
672 : // url
673 : // : STRING
674 :
675 12 : void CSS1Parser::ParseStyleSheet()
676 : {
677 12 : LOOP_CHECK_DECL
678 :
679 : // import*
680 12 : bool bDone = false;
681 36 : while( !bDone && IsParserWorking() )
682 : {
683 12 : LOOP_CHECK_CHECK( "Endlos-Schleife in ParseStyleSheet()/import *" )
684 :
685 12 : switch( nToken )
686 : {
687 : case CSS1_IMPORT_SYM:
688 : // IMPORT_SYM url
689 : // url ueberspringen wir ungeprueft
690 0 : nToken = GetNextToken();
691 0 : break;
692 : case CSS1_IDENT: // Look-Aheads
693 : case CSS1_DOT_W_WS:
694 : case CSS1_HASH:
695 : // /Feature: PrintExt
696 : case CSS1_PAGE_SYM:
697 : // /Feature: PrintExt
698 : // rule
699 12 : bDone = true;
700 12 : break;
701 : default:
702 : // Fehlerbehandlung: ueberlesen
703 0 : break;
704 : }
705 :
706 12 : if( !bDone )
707 0 : nToken = GetNextToken();
708 : }
709 :
710 12 : LOOP_CHECK_RESTART
711 :
712 : // rule *
713 54 : while( IsParserWorking() )
714 : {
715 30 : LOOP_CHECK_CHECK( "Endlos-Schleife in ParseStyleSheet()/rule *" )
716 :
717 30 : switch( nToken )
718 : {
719 : case CSS1_IDENT: // Look-Aheads
720 : case CSS1_DOT_W_WS:
721 : case CSS1_HASH:
722 : // /Feature: PrintExt
723 : case CSS1_PAGE_SYM:
724 : // /Feature: PrintExt
725 : // rule
726 30 : ParseRule();
727 30 : break;
728 : default:
729 : // Fehlerbehandlung: ueberlesen
730 0 : nToken = GetNextToken();
731 0 : break;
732 : }
733 : }
734 12 : }
735 :
736 : // rule
737 : // : selector [ ',' selector ]*
738 : // '{' declaration [ ';' declaration ]* '}'
739 :
740 30 : void CSS1Parser::ParseRule()
741 : {
742 : // selector
743 30 : CSS1Selector *pSelector = ParseSelector();
744 30 : if( !pSelector )
745 0 : return;
746 :
747 : // Selektor verarbeiten
748 30 : if( SelectorParsed( pSelector, true ) )
749 0 : delete pSelector;
750 :
751 30 : LOOP_CHECK_DECL
752 :
753 : // [ ',' selector ]*
754 60 : while( CSS1_COMMA==nToken && IsParserWorking() )
755 : {
756 0 : LOOP_CHECK_CHECK( "Endlos-Schleife in ParseRule()/selector *" )
757 :
758 : // ',' ueberelesen
759 0 : nToken = GetNextToken();
760 :
761 : // selector
762 0 : pSelector = ParseSelector();
763 0 : if( !pSelector )
764 0 : return;
765 :
766 : // Selektor verarbeiten
767 0 : if( SelectorParsed( pSelector, false ) )
768 0 : delete pSelector;
769 : }
770 :
771 : // '{'
772 30 : if( CSS1_OBRACE != nToken )
773 0 : return;
774 30 : nToken = GetNextToken();
775 :
776 : // declaration
777 30 : OUString aProperty;
778 30 : CSS1Expression *pExpr = ParseDeclaration( aProperty );
779 30 : if( !pExpr )
780 0 : return;
781 :
782 : // expression verarbeiten
783 30 : if( DeclarationParsed( aProperty, pExpr ) )
784 30 : delete pExpr;
785 :
786 30 : LOOP_CHECK_RESTART
787 :
788 : // [ ';' declaration ]*
789 102 : while( CSS1_SEMICOLON==nToken && IsParserWorking() )
790 : {
791 42 : LOOP_CHECK_CHECK( "Endlos-Schleife in ParseRule()/declaration *" )
792 :
793 : // ';'
794 42 : nToken = GetNextToken();
795 :
796 : // declaration
797 42 : if( CSS1_IDENT == nToken )
798 : {
799 42 : CSS1Expression *pExp = ParseDeclaration( aProperty );
800 42 : if( pExp )
801 : {
802 : // expression verarbeiten
803 42 : if( DeclarationParsed( aProperty, pExp ) )
804 42 : delete pExp;
805 : }
806 : }
807 : }
808 :
809 : // '}'
810 30 : if( CSS1_CBRACE == nToken )
811 30 : nToken = GetNextToken();
812 : }
813 :
814 : // selector
815 : // : simple_selector+ [ ':' pseudo_element ]?
816 :
817 : // simple_selector
818 : // : element_name [ DOT_WO_WS class ]?
819 : // | DOT_W_WS class
820 : // | id_selector
821 :
822 : // element_name
823 : // : IDENT
824 :
825 : // class
826 : // : IDENT
827 :
828 : // id_selector
829 : // : '#' IDENT
830 :
831 : // pseude_element
832 : // : IDENT
833 :
834 30 : CSS1Selector *CSS1Parser::ParseSelector()
835 : {
836 30 : CSS1Selector *pRoot = 0, *pLast = 0;
837 :
838 30 : bool bDone = false;
839 30 : CSS1Selector *pNew = 0;
840 :
841 30 : LOOP_CHECK_DECL
842 :
843 : // simple_selector+
844 120 : while( !bDone && IsParserWorking() )
845 : {
846 60 : LOOP_CHECK_CHECK( "Endlos-Schleife in ParseSelector()" )
847 :
848 60 : bool bNextToken = true;
849 :
850 60 : switch( nToken )
851 : {
852 : case CSS1_IDENT:
853 : {
854 : // element_name [ DOT_WO_WS class ]?
855 :
856 : // element_name
857 20 : OUString aElement = aToken;
858 20 : CSS1SelectorType eType = CSS1_SELTYPE_ELEMENT;
859 20 : nToken = GetNextToken();
860 :
861 20 : if( CSS1_DOT_WO_WS == nToken )
862 : {
863 : // DOT_WO_WS
864 12 : nToken = GetNextToken();
865 :
866 : // class
867 12 : if( CSS1_IDENT == nToken )
868 : {
869 12 : aElement += "." + aToken;
870 12 : eType = CSS1_SELTYPE_ELEM_CLASS;
871 : }
872 : else
873 : {
874 : // class fehlt
875 0 : return pRoot;
876 : }
877 : }
878 : else
879 : {
880 : // das war jetzt ein Look-Ahead
881 8 : bNextToken = false;
882 : }
883 20 : pNew = new CSS1Selector( eType, aElement );
884 : }
885 20 : break;
886 : case CSS1_DOT_W_WS:
887 : // DOT_W_WS class
888 :
889 : // DOT_W_WS
890 0 : nToken = GetNextToken();
891 :
892 0 : if( CSS1_IDENT==nToken )
893 : {
894 : // class
895 0 : pNew = new CSS1Selector( CSS1_SELTYPE_CLASS, aToken );
896 : }
897 : else
898 : {
899 : // class fehlt
900 0 : return pRoot;
901 : }
902 0 : break;
903 : case CSS1_HASH:
904 : // '#' id_selector
905 :
906 : // '#'
907 0 : nToken = GetNextToken();
908 :
909 0 : if( CSS1_IDENT==nToken )
910 : {
911 : // id_selector
912 0 : pNew = new CSS1Selector( CSS1_SELTYPE_ID, aToken );
913 : }
914 : else
915 : {
916 : // id_selector fehlt
917 0 : return pRoot;
918 : }
919 0 : break;
920 :
921 : // /Feature: PrintExt
922 : case CSS1_PAGE_SYM:
923 : {
924 : // @page
925 10 : pNew = new CSS1Selector( CSS1_SELTYPE_PAGE, aToken );
926 : }
927 10 : break;
928 : // /Feature: PrintExt
929 :
930 : default:
931 : // wir wissen nicht was kommt, also aufhoehren
932 30 : bDone = true;
933 30 : break;
934 : }
935 :
936 : // falls ein Selektor angelegt wurd, ihn speichern
937 60 : if( pNew )
938 : {
939 : OSL_ENSURE( (pRoot!=0) == (pLast!=0),
940 : "Root-Selektor, aber kein Last" );
941 30 : if( pLast )
942 0 : pLast->SetNext( pNew );
943 : else
944 30 : pRoot = pNew;
945 :
946 30 : pLast = pNew;
947 30 : pNew = 0;
948 : }
949 :
950 60 : if( bNextToken && !bDone )
951 22 : nToken = GetNextToken();
952 : }
953 :
954 30 : if( !pRoot )
955 : {
956 : // simple_selector fehlt
957 0 : return pRoot;
958 : }
959 :
960 : // [ ':' pseudo_element ]?
961 30 : if( CSS1_COLON==nToken && IsParserWorking() )
962 : {
963 : // ':' pseudo element
964 8 : nToken = GetNextToken();
965 8 : if( CSS1_IDENT==nToken )
966 : {
967 8 : pLast->SetNext( new CSS1Selector(CSS1_SELTYPE_PSEUDO,aToken) );
968 8 : nToken = GetNextToken();
969 : }
970 : else
971 : {
972 : // pseudo_element fehlt
973 0 : return pRoot;
974 : }
975 : }
976 :
977 30 : return pRoot;
978 : }
979 :
980 : // declaration
981 : // : property ':' expr prio?
982 : // | /* empty */
983 :
984 : // expression
985 : // : term [ operator term ]*
986 :
987 : // term
988 : // : unary_operator?
989 : // [ NUMBER | STRING | PERCENTAGE | LENGTH | EMS | EXS | IDENT |
990 : // HEXCOLOR | URL | RGB ]
991 :
992 : // operator
993 : // : '/' | ',' | /* empty */
994 :
995 : // unary_operator
996 : // : '-' | '+'
997 :
998 : // property
999 : // : ident
1000 :
1001 : // das Vorzeichen wird nur fuer numerische Werte (ausser PERCENTAGE)
1002 : // beruecksichtigt und wird auf nValue angewendet!
1003 5354 : CSS1Expression *CSS1Parser::ParseDeclaration( OUString& rProperty )
1004 : {
1005 5354 : CSS1Expression *pRoot = 0, *pLast = 0;
1006 :
1007 : // property
1008 5354 : if( CSS1_IDENT != nToken )
1009 : {
1010 : // property fehlt
1011 0 : return pRoot;
1012 : }
1013 5354 : rProperty = aToken;
1014 :
1015 5354 : nToken = GetNextToken();
1016 :
1017 : // ':'
1018 5354 : if( CSS1_COLON != nToken )
1019 : {
1020 : // ':' fehlt
1021 0 : return pRoot;
1022 : }
1023 5354 : nToken = GetNextToken();
1024 :
1025 : // term [operator term]*
1026 : // hier sind wir sehr lax, was die Syntax angeht, sollte aber kein
1027 : // Problem sein
1028 5354 : bool bDone = false;
1029 5354 : sal_Unicode cSign = 0, cOp = 0;
1030 5354 : CSS1Expression *pNew = 0;
1031 :
1032 5354 : LOOP_CHECK_DECL
1033 :
1034 22450 : while( !bDone && IsParserWorking() )
1035 : {
1036 11742 : LOOP_CHECK_CHECK( "Endlos-Schleife in ParseDeclaration()" )
1037 :
1038 11742 : switch( nToken )
1039 : {
1040 : case CSS1_MINUS:
1041 2 : cSign = '-';
1042 2 : break;
1043 :
1044 : case CSS1_PLUS:
1045 0 : cSign = '+';
1046 0 : break;
1047 :
1048 : case CSS1_NUMBER:
1049 : case CSS1_LENGTH:
1050 : case CSS1_PIXLENGTH:
1051 : case CSS1_EMS:
1052 : case CSS1_EMX:
1053 5306 : if( '-'==cSign )
1054 2 : nValue = -nValue;
1055 : //fall-through
1056 : case CSS1_STRING:
1057 : case CSS1_PERCENTAGE:
1058 : case CSS1_IDENT:
1059 : case CSS1_URL:
1060 : case CSS1_RGB:
1061 : case CSS1_HEXCOLOR:
1062 7460 : pNew = new CSS1Expression( nToken, aToken, nValue, cOp );
1063 7460 : nValue = 0; // sonst landet das auch im naechsten Ident
1064 7460 : cSign = 0;
1065 7460 : cOp = 0;
1066 7460 : break;
1067 :
1068 : case CSS1_SLASH:
1069 0 : cOp = '/';
1070 0 : cSign = 0;
1071 0 : break;
1072 :
1073 : case CSS1_COMMA:
1074 0 : cOp = ',';
1075 0 : cSign = 0;
1076 0 : break;
1077 :
1078 : default:
1079 4280 : bDone = true;
1080 4280 : break;
1081 : }
1082 :
1083 : // falls ein Expression angelegt wurde, diesen speichern
1084 11742 : if( pNew )
1085 : {
1086 : OSL_ENSURE( (pRoot!=0) == (pLast!=0),
1087 : "Root-Selektor, aber kein Last" );
1088 7460 : if( pLast )
1089 2106 : pLast->SetNext( pNew );
1090 : else
1091 5354 : pRoot = pNew;
1092 :
1093 7460 : pLast = pNew;
1094 7460 : pNew = 0;
1095 : }
1096 :
1097 11742 : if( !bDone )
1098 7462 : nToken = GetNextToken();
1099 : }
1100 :
1101 5354 : if( !pRoot )
1102 : {
1103 : // term fehlt
1104 0 : return pRoot;
1105 : }
1106 :
1107 : // prio?
1108 5354 : if( CSS1_IMPORTANT_SYM==nToken )
1109 : {
1110 : // IMPORTANT_SYM
1111 0 : nToken = GetNextToken();
1112 : }
1113 :
1114 5354 : return pRoot;
1115 : }
1116 :
1117 22 : CSS1Parser::CSS1Parser()
1118 : : bWhiteSpace(false)
1119 : , bEOF(false)
1120 : , cNextCh(0)
1121 : , nInPos(0)
1122 : , nlLineNr(0)
1123 : , nlLinePos(0)
1124 : , nValue(0)
1125 : , eState(CSS1_PAR_ACCEPTED)
1126 22 : , nToken(CSS1_NULL)
1127 : {
1128 22 : }
1129 :
1130 22 : CSS1Parser::~CSS1Parser()
1131 : {
1132 22 : }
1133 :
1134 12 : bool CSS1Parser::ParseStyleSheet( const OUString& rIn )
1135 : {
1136 12 : OUString aTmp( rIn );
1137 :
1138 : sal_Unicode c;
1139 88 : while( !aTmp.isEmpty() &&
1140 28 : ( ' '==(c=aTmp[0]) || '\t'==c || '\r'==c || '\n'==c ) )
1141 32 : aTmp = aTmp.copy( 1, aTmp.getLength() - 1 );
1142 :
1143 104 : while( !aTmp.isEmpty() && ( ' '==(c=aTmp[aTmp.getLength()-1])
1144 36 : || '\t'==c || '\r'==c || '\n'==c ) )
1145 40 : aTmp = aTmp.copy( 0, aTmp.getLength()-1 );
1146 :
1147 : // SGML-Kommentare entfernen
1148 24 : if( aTmp.getLength() >= 4 &&
1149 12 : aTmp.startsWith( "<!--" ) )
1150 0 : aTmp = aTmp.copy( 4, aTmp.getLength() - 4 );
1151 :
1152 24 : if( aTmp.getLength() >=3 &&
1153 12 : aTmp.endsWith("-->") )
1154 0 : aTmp = aTmp.copy( 0, aTmp.getLength() - 3 );
1155 :
1156 12 : if( aTmp.isEmpty() )
1157 0 : return true;
1158 :
1159 12 : InitRead( aTmp );
1160 :
1161 12 : ParseStyleSheet();
1162 :
1163 12 : return true;
1164 : }
1165 :
1166 1088 : bool CSS1Parser::ParseStyleOption( const OUString& rIn )
1167 : {
1168 1088 : if( rIn.isEmpty() )
1169 0 : return true;
1170 :
1171 1088 : InitRead( rIn );
1172 :
1173 : // fdo#41796: skip over spurious semicolons
1174 2176 : while (CSS1_SEMICOLON == nToken)
1175 : {
1176 0 : nToken = GetNextToken();
1177 : }
1178 :
1179 1088 : OUString aProperty;
1180 1088 : CSS1Expression *pExpr = ParseDeclaration( aProperty );
1181 1088 : if( !pExpr )
1182 : {
1183 0 : return false;
1184 : }
1185 :
1186 : // expression verarbeiten
1187 1088 : if( DeclarationParsed( aProperty, pExpr ) )
1188 1088 : delete pExpr;
1189 :
1190 1088 : LOOP_CHECK_DECL
1191 :
1192 : // [ ';' declaration ]*
1193 6384 : while( CSS1_SEMICOLON==nToken && IsParserWorking() )
1194 : {
1195 4208 : LOOP_CHECK_CHECK( "Endlos-Schleife in ParseStyleOption()" )
1196 :
1197 4208 : nToken = GetNextToken();
1198 4208 : if( CSS1_IDENT==nToken )
1199 : {
1200 4194 : CSS1Expression *pExp = ParseDeclaration( aProperty );
1201 4194 : if( pExp )
1202 : {
1203 : // expression verarbeiten
1204 4194 : if( DeclarationParsed( aProperty, pExp ) )
1205 4194 : delete pExp;
1206 : }
1207 : }
1208 : }
1209 :
1210 1088 : return true;
1211 : }
1212 :
1213 0 : bool CSS1Parser::SelectorParsed( CSS1Selector* /* pSelector */, bool /*bFirst*/ )
1214 : {
1215 : // Selektor loeschen
1216 0 : return true;
1217 : }
1218 :
1219 0 : bool CSS1Parser::DeclarationParsed( const OUString& /*rProperty*/,
1220 : const CSS1Expression * /* pExpr */ )
1221 : {
1222 : // Deklaration loeschen
1223 0 : return true;
1224 : }
1225 :
1226 76 : CSS1Selector::~CSS1Selector()
1227 : {
1228 38 : delete pNext;
1229 38 : }
1230 :
1231 14920 : CSS1Expression::~CSS1Expression()
1232 : {
1233 7460 : delete pNext;
1234 7460 : }
1235 :
1236 0 : bool CSS1Expression::GetURL( OUString& rURL ) const
1237 : {
1238 : OSL_ENSURE( CSS1_URL==eType, "CSS1-Ausruck ist keine Farbe URL" );
1239 :
1240 : OSL_ENSURE( aValue.startsWithIgnoreAsciiCase( "url" ) &&
1241 : aValue.getLength() > 5 &&
1242 : '(' == aValue[3] &&
1243 : ')' == aValue[aValue.getLength()-1],
1244 : "keine gueltiges URL(...)" );
1245 :
1246 0 : bool bRet = false;
1247 :
1248 0 : if( aValue.getLength() > 5 )
1249 : {
1250 0 : rURL = aValue.copy( 4, aValue.getLength() - 5 );
1251 0 : rURL = comphelper::string::strip(rURL, ' ');
1252 0 : bRet = true;
1253 : }
1254 :
1255 0 : return bRet;
1256 : }
1257 :
1258 1052 : bool CSS1Expression::GetColor( Color &rColor ) const
1259 : {
1260 : OSL_ENSURE( CSS1_IDENT==eType || CSS1_RGB==eType ||
1261 : CSS1_HEXCOLOR==eType || CSS1_STRING==eType,
1262 : "CSS1-Ausruck kann keine Farbe sein" );
1263 :
1264 1052 : bool bRet = false;
1265 1052 : sal_uInt32 nColor = SAL_MAX_UINT32;
1266 :
1267 1052 : switch( eType )
1268 : {
1269 : case CSS1_RGB:
1270 : {
1271 0 : sal_uInt8 aColors[3] = { 0, 0, 0 };
1272 :
1273 0 : if (!aValue.startsWithIgnoreAsciiCase( "rgb" ) || aValue.getLength() < 6 ||
1274 0 : aValue[3] != '(' || aValue[aValue.getLength()-1] != ')')
1275 : {
1276 0 : break;
1277 : }
1278 :
1279 0 : OUString aColorStr(aValue.copy(4, aValue.getLength() - 5));
1280 :
1281 0 : sal_Int32 nPos = 0;
1282 0 : sal_uInt16 nCol = 0;
1283 :
1284 0 : while( nCol < 3 && nPos < aColorStr.getLength() )
1285 : {
1286 : sal_Unicode c;
1287 0 : while( nPos < aColorStr.getLength() &&
1288 0 : ((c=aColorStr[nPos]) == ' ' || c == '\t' ||
1289 0 : c == '\n' || c== '\r' ) )
1290 0 : nPos++;
1291 :
1292 0 : sal_Int32 nEnd = aColorStr.indexOf( ',', nPos );
1293 0 : OUString aNumber;
1294 0 : if( nEnd == -1 )
1295 : {
1296 0 : aNumber = aColorStr.copy(nPos);
1297 0 : nPos = aColorStr.getLength();
1298 : }
1299 : else
1300 : {
1301 0 : aNumber = aColorStr.copy( nPos, nEnd-nPos );
1302 0 : nPos = nEnd+1;
1303 : }
1304 :
1305 0 : sal_uInt16 nNumber = (sal_uInt16)aNumber.toInt32();
1306 0 : if( aNumber.indexOf('%') >= 0 )
1307 : {
1308 0 : if( nNumber > 100 )
1309 0 : nNumber = 100;
1310 0 : nNumber *= 255;
1311 0 : nNumber /= 100;
1312 : }
1313 0 : else if( nNumber > 255 )
1314 0 : nNumber = 255;
1315 :
1316 0 : aColors[nCol] = (sal_uInt8)nNumber;
1317 0 : nCol ++;
1318 0 : }
1319 :
1320 0 : rColor.SetRed( aColors[0] );
1321 0 : rColor.SetGreen( aColors[1] );
1322 0 : rColor.SetBlue( aColors[2] );
1323 :
1324 0 : bRet = true; // etwas anderes als eine Farbe kann es nicht sein
1325 : }
1326 0 : break;
1327 :
1328 : case CSS1_IDENT:
1329 : case CSS1_STRING:
1330 : {
1331 0 : OUString aTmp( aValue.toAsciiUpperCase() );
1332 0 : nColor = GetHTMLColor( aTmp );
1333 0 : bRet = nColor != SAL_MAX_UINT32;
1334 : }
1335 0 : if( bRet || CSS1_STRING != eType || aValue.isEmpty() ||
1336 0 : aValue[0] != '#' )
1337 0 : break;
1338 :
1339 : case CSS1_HEXCOLOR:
1340 : {
1341 : // HACK fuer MS-IE: DIe Farbe kann auch in einem String stehen
1342 1052 : sal_Int32 nOffset = CSS1_STRING==eType ? 1 : 0;
1343 1052 : bool bDouble = aValue.getLength()-nOffset == 3;
1344 1052 : sal_Int32 i = nOffset, nEnd = (bDouble ? 3 : 6) + nOffset;
1345 :
1346 1052 : nColor = 0;
1347 7364 : for( ; i<nEnd; i++ )
1348 : {
1349 12624 : sal_Unicode c = (i<aValue.getLength() ? aValue[i]
1350 12624 : : '0' );
1351 6312 : if( c >= '0' && c <= '9' )
1352 6292 : c -= 48;
1353 20 : else if( c >= 'A' && c <= 'F' )
1354 0 : c -= 55;
1355 20 : else if( c >= 'a' && c <= 'f' )
1356 20 : c -= 87;
1357 : else
1358 0 : c = 16;
1359 :
1360 6312 : nColor *= 16;
1361 6312 : if( c<16 )
1362 6312 : nColor += c;
1363 6312 : if( bDouble )
1364 : {
1365 0 : nColor *= 16;
1366 0 : if( c<16 )
1367 0 : nColor += c;
1368 : }
1369 : }
1370 1052 : bRet = true;
1371 : }
1372 1052 : break;
1373 : default:
1374 : ;
1375 : }
1376 :
1377 1052 : if( bRet && nColor!=SAL_MAX_UINT32 )
1378 : {
1379 1052 : rColor.SetRed( (sal_uInt8)((nColor & 0x00ff0000UL) >> 16) );
1380 1052 : rColor.SetGreen( (sal_uInt8)((nColor & 0x0000ff00UL) >> 8) );
1381 1052 : rColor.SetBlue( (sal_uInt8)(nColor & 0x000000ffUL) );
1382 : }
1383 :
1384 1052 : return bRet;
1385 270 : }
1386 :
1387 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|