1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: parcss1.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
39 #include <rtl/ustrbuf.hxx>
40 #include <tools/debug.hxx>
41 #include <vcl/svapp.hxx>
42 #include <svtools/htmltokn.h>
44 #include "css1kywd.hxx"
45 #include "parcss1.hxx"
48 // Loop-Check: Um Endlos-Schleifen zu vermeiden, wird in jeder
49 // Schalife geprueft, ob ein Fortschritt in der Eingabe-Position
55 #define LOOP_CHECK_DECL \
56 xub_StrLen nOldInPos = STRING_MAXLEN;
57 #define LOOP_CHECK_RESTART \
58 nOldInPos = STRING_MAXLEN;
59 #define LOOP_CHECK_CHECK( where ) \
60 DBG_ASSERT( nOldInPos!=nInPos || cNextCh==(sal_Unicode)EOF, where ); \
61 if( nOldInPos==nInPos && cNextCh!=(sal_Unicode)EOF ) \
68 #define LOOP_CHECK_DECL
69 #define LOOP_CHECK_RESTART
70 #define LOOP_CHECK_CHECK( where )
76 const sal_Int32 MAX_LEN
= 1024;
80 void CSS1Parser::InitRead( const String
& rIn
)
85 bWhiteSpace
= TRUE
; // Wenn noch nichts gelesen wurde ist das wie WS
87 eState
= CSS1_PAR_WORKING
;
92 cNextCh
= GetNextChar();
93 nToken
= GetNextToken();
96 sal_Unicode
CSS1Parser::GetNextChar()
98 if( nInPos
>= aIn
.Len() )
101 return (sal_Unicode
)EOF
;
104 sal_Unicode c
= aIn
.GetChar( nInPos
);
120 // Diese Funktion realisiert den in
122 // http://www.w3.orh/pub/WWW/TR/WD-css1.html
123 // bzw. http://www.w3.orh/pub/WWW/TR/WD-css1-960220.html
125 // beschriebenen Scanner fuer CSS1. Es handelt sich um eine direkte
126 // Umsetzung der dort beschriebenen Lex-Grammatik
128 CSS1Token
CSS1Parser::GetNextToken()
130 CSS1Token nRet
= CSS1_NULL
;
134 // Merken, ob davor White-Space gelesen wurde
135 BOOL bPrevWhiteSpace
= bWhiteSpace
;
141 case '/': // COMMENT | '/'
143 cNextCh
= GetNextChar();
147 cNextCh
= GetNextChar();
149 BOOL bAsterix
= FALSE
;
150 while( !(bAsterix
&& '/'==cNextCh
) && !IsEOF() )
152 bAsterix
= ('*'==cNextCh
);
153 cNextCh
= GetNextChar();
165 case '@': // '@import' | '@XXX'
167 cNextCh
= GetNextChar();
168 if( ('A' <= cNextCh
&& cNextCh
<= 'Z') ||
169 ('a' <= cNextCh
&& cNextCh
<= 'z') )
171 // den naechsten Identifer scannen
172 ::rtl::OUStringBuffer
sTmpBuffer( 32L );
174 sTmpBuffer
.append( cNextCh
);
175 cNextCh
= GetNextChar();
176 } while( ('A' <= cNextCh
&& cNextCh
<= 'Z') ||
177 ('a' <= cNextCh
&& cNextCh
<= 'z') ||
178 ('0' <= cNextCh
&& cNextCh
<= '9') ||
179 '-'==cNextCh
&& !IsEOF() );
181 aToken
+= String(sTmpBuffer
.makeStringAndClear());
183 // und schauen, ob wir ihn kennen
184 switch( aToken
.GetChar(0) )
188 if( aToken
.EqualsIgnoreCaseAscii(sCSS1_import
) )
189 nRet
= CSS1_IMPORT_SYM
;
191 // /Feature: PrintExt
194 if( aToken
.EqualsIgnoreCaseAscii(sCSS1_page
) )
195 nRet
= CSS1_PAGE_SYM
;
197 // /Feature: PrintExt
200 // Fehlerbehandlung: '@ident' und alles bis
201 // zu einem Semikolon der dem Ende des folgenden
203 if( CSS1_NULL
==nRet
)
206 USHORT nBlockLvl
= 0;
207 sal_Unicode cQuoteCh
= 0;
208 BOOL bDone
= FALSE
, bEscape
= FALSE
;
209 while( !bDone
&& !IsEOF() )
211 BOOL bOldEscape
= bEscape
;
216 if( !cQuoteCh
&& !bOldEscape
)
220 if( !cQuoteCh
&& !bOldEscape
)
221 bDone
= nBlockLvl
==0;
224 if( !cQuoteCh
&& !bOldEscape
)
225 bDone
= --nBlockLvl
==0;
233 if( cQuoteCh
== cNextCh
)
247 cNextCh
= GetNextChar();
256 case '!': // '!' 'legal' | '!' 'important' | syntax error
258 // White Space ueberlesen
259 cNextCh
= GetNextChar();
260 while( ( ' ' == cNextCh
||
261 (cNextCh
>= 0x09 && cNextCh
<= 0x0d) ) && !IsEOF() )
264 cNextCh
= GetNextChar();
267 if( 'i'==cNextCh
|| 'I'==cNextCh
)
269 // den naechsten Identifer scannen
270 ::rtl::OUStringBuffer
sTmpBuffer( 32L );
272 sTmpBuffer
.append( cNextCh
);
273 cNextCh
= GetNextChar();
274 } while( ('A' <= cNextCh
&& cNextCh
<= 'Z') ||
275 ('a' <= cNextCh
&& cNextCh
<= 'z') ||
276 ('0' <= cNextCh
&& cNextCh
<= '9') ||
277 '-' == cNextCh
&& !IsEOF() );
279 aToken
+= String(sTmpBuffer
.makeStringAndClear());
281 if( ('i'==aToken
.GetChar(0) || 'I'==aToken
.GetChar(0)) &&
282 aToken
.EqualsIgnoreCaseAscii(sCSS1_important
) )
285 nRet
= CSS1_IMPORTANT_SYM
;
289 // Fehlerbehandlung: '!' ignorieren, IDENT nicht
298 // Fehlerbehandlung: '!' ignorieren
307 // \... geht noch nicht!!!
308 sal_Unicode cQuoteChar
= cNextCh
;
309 cNextCh
= GetNextChar();
311 ::rtl::OUStringBuffer
sTmpBuffer( MAX_LEN
);
313 sTmpBuffer
.append( cNextCh
);
314 cNextCh
= GetNextChar();
315 } while( cQuoteChar
!= cNextCh
&& !IsEOF() );
317 aToken
+= String(sTmpBuffer
.makeStringAndClear());
332 case '9': // NUMBER | PERCENTAGE | LENGTH
334 // die aktuelle Position retten
335 xub_StrLen nInPosSave
= nInPos
;
336 sal_Unicode cNextChSave
= cNextCh
;
337 sal_uInt32 nlLineNrSave
= nlLineNr
;
338 sal_uInt32 nlLinePosSave
= nlLinePos
;
339 BOOL bEOFSave
= bEOF
;
341 // erstmal versuchen eine Hex-Zahl zu scannen
342 ::rtl::OUStringBuffer
sTmpBuffer( 16 );
344 sTmpBuffer
.append( cNextCh
);
345 cNextCh
= GetNextChar();
346 } while( sTmpBuffer
.getLength() < 7 &&
347 ( ('0'<=cNextCh
&& '9'>=cNextCh
) ||
348 ('A'<=cNextCh
&& 'F'>=cNextCh
) ||
349 ('a'<=cNextCh
&& 'f'>=cNextCh
) ) &&
352 if( sTmpBuffer
.getLength()==6 )
354 // wir haben eine hexadezimale Farbe gefunden
355 aToken
+= String(sTmpBuffer
.makeStringAndClear());
356 nRet
= CSS1_HEXCOLOR
;
362 // sonst versuchen wir es mit einer Zahl
364 cNextCh
= cNextChSave
;
365 nlLineNr
= nlLineNrSave
;
366 nlLinePos
= nlLinePosSave
;
369 // erstmal die Zahl scannen
370 sTmpBuffer
.setLength( 0L );
372 sTmpBuffer
.append( cNextCh
);
373 cNextCh
= GetNextChar();
374 } while( (('0'<=cNextCh
&& '9'>=cNextCh
) || '.'==cNextCh
) &&
377 aToken
+= String(sTmpBuffer
.makeStringAndClear());
378 nValue
= aToken
.ToDouble();
380 // White Space ueberlesen
381 while( ( ' ' == cNextCh
||
382 (cNextCh
>= 0x09 && cNextCh
<= 0x0d) ) && !IsEOF() )
385 cNextCh
= GetNextChar();
388 // und nun Schauen, ob es eine Einheit gibt
391 case '%': // PERCENTAGE
393 nRet
= CSS1_PERCENTAGE
;
397 case 'C': // LENGTH cm | LENGTH IDENT
399 case 'E': // LENGTH (em | ex) | LENGTH IDENT
401 case 'I': // LENGTH inch | LENGTH IDENT
403 case 'P': // LENGTH (pt | px | pc) | LENGTH IDENT
405 case 'M': // LENGTH mm | LENGTH IDENT
407 // die aktuelle Position retten
408 xub_StrLen nInPosOld
= nInPos
;
409 sal_Unicode cNextChOld
= cNextCh
;
410 ULONG nlLineNrOld
= nlLineNr
;
411 ULONG nlLinePosOld
= nlLinePos
;
414 // den naechsten Identifer scannen
416 ::rtl::OUStringBuffer
sTmpBuffer2( 64L );
418 sTmpBuffer2
.append( cNextCh
);
419 cNextCh
= GetNextChar();
420 } while( ( ('A' <= cNextCh
&& cNextCh
<= 'Z') ||
421 ('a' <= cNextCh
&& cNextCh
<= 'z') ||
422 ('0' <= cNextCh
&& cNextCh
<= '9') ||
423 '-'==cNextCh
) && !IsEOF() );
425 aIdent
+= String(sTmpBuffer2
.makeStringAndClear());
427 // Ist es eine Einheit?
428 const sal_Char
*pCmp1
= 0, *pCmp2
= 0, *pCmp3
= 0;
429 double nScale1
= 1., nScale2
= 1., nScale3
= 1.;
430 CSS1Token nToken1
= CSS1_LENGTH
,
431 nToken2
= CSS1_LENGTH
,
432 nToken3
= CSS1_LENGTH
;
433 switch( aIdent
.GetChar(0) )
437 pCmp1
= sCSS1_UNIT_cm
;
438 nScale1
= (72.*20.)/2.54; // twip
442 pCmp1
= sCSS1_UNIT_em
;
445 pCmp2
= sCSS1_UNIT_ex
;
450 pCmp1
= sCSS1_UNIT_inch
;
451 nScale1
= 72.*20.; // twip
455 pCmp1
= sCSS1_UNIT_mm
;
456 nScale1
= (72.*20.)/25.4; // twip
460 pCmp1
= sCSS1_UNIT_pt
;
461 nScale1
= 20.; // twip
463 pCmp2
= sCSS1_UNIT_pc
;
464 nScale2
= 12.*20.; // twip
466 pCmp3
= sCSS1_UNIT_px
;
467 nToken3
= CSS1_PIXLENGTH
;
472 DBG_ASSERT( pCmp1
, "Wo kommt das erste Zeichen her?" );
473 if( aIdent
.EqualsIgnoreCaseAscii(pCmp1
) )
479 aIdent
.EqualsIgnoreCaseAscii(pCmp2
) )
485 aIdent
.EqualsIgnoreCaseAscii(pCmp3
) )
495 if( CSS1_LENGTH
==nRet
&& nScale
!=1.0 )
498 if( nRet
== CSS1_NUMBER
)
501 cNextCh
= cNextChOld
;
502 nlLineNr
= nlLineNrOld
;
503 nlLinePos
= nlLinePosOld
;
513 default: // NUMBER IDENT
522 // link/visited/active abfangen !!!
526 case '.': // DOT_W_WS | DOT_WO_WS
527 nRet
= bPrevWhiteSpace
? CSS1_DOT_W_WS
: CSS1_DOT_WO_WS
;
530 // case '/': siehe oben
549 nRet
= CSS1_SEMICOLON
;
557 cNextCh
= GetNextChar();
558 if( ('0'<=cNextCh
&& '9'>=cNextCh
) ||
559 ('a'<=cNextCh
&& 'f'>=cNextCh
) ||
560 ('A'<=cNextCh
&& 'F'>=cNextCh
) )
562 // die aktuelle Position retten
563 xub_StrLen nInPosSave
= nInPos
;
564 sal_Unicode cNextChSave
= cNextCh
;
565 ULONG nlLineNrSave
= nlLineNr
;
566 ULONG nlLinePosSave
= nlLinePos
;
567 BOOL bEOFSave
= bEOF
;
569 // erstmal versuchen eine Hex-Zahl zu scannen
570 ::rtl::OUStringBuffer
sTmpBuffer( 6L );
572 sTmpBuffer
.append( cNextCh
);
573 cNextCh
= GetNextChar();
574 } while( sTmpBuffer
.getLength() < 7 &&
575 ( ('0'<=cNextCh
&& '9'>=cNextCh
) ||
576 ('A'<=cNextCh
&& 'F'>=cNextCh
) ||
577 ('a'<=cNextCh
&& 'f'>=cNextCh
) ) &&
580 if( sTmpBuffer
.getLength()==6 || sTmpBuffer
.getLength()==3 )
582 // wir haben eine hexadezimale Farbe gefunden
583 aToken
+= String(sTmpBuffer
.makeStringAndClear());
584 nRet
= CSS1_HEXCOLOR
;
590 // sonst versuchen wir es mit einer Zahl
592 cNextCh
= cNextChSave
;
593 nlLineNr
= nlLineNrSave
;
594 nlLinePos
= nlLinePosSave
;
605 case '\n': // White-Space
609 case (sal_Unicode
)EOF
:
612 eState
= CSS1_PAR_ACCEPTED
;
618 default: // IDENT | syntax error
620 if( ('A' <= cNextCh
&& cNextCh
<= 'Z') ||
621 ('a' <= cNextCh
&& cNextCh
<= 'z') )
625 BOOL bHexColor
= TRUE
;
627 // den naechsten Identifer scannen
628 ::rtl::OUStringBuffer
sTmpBuffer( 64L );
630 sTmpBuffer
.append( cNextCh
);
633 bHexColor
= sTmpBuffer
.getLength()<7 &&
634 ( ('0'<=cNextCh
&& '9'>=cNextCh
) ||
635 ('A'<=cNextCh
&& 'F'>=cNextCh
) ||
636 ('a'<=cNextCh
&& 'f'>=cNextCh
) );
638 cNextCh
= GetNextChar();
639 // TODO: AlphaNumeric
640 } while( ( ('0'<=cNextCh
&& '9'>=cNextCh
) ||
641 ('A'<=cNextCh
&& 'Z'>=cNextCh
) ||
642 ('a'<=cNextCh
&& 'z'>=cNextCh
) ||
646 aToken
+= String(sTmpBuffer
.makeStringAndClear());
648 if( bHexColor
&& sTmpBuffer
.getLength()==6 )
651 nRet
= CSS1_HEXCOLOR
;
656 ( (('u'==aToken
.GetChar(0) || 'U'==aToken
.GetChar(0)) &&
657 aToken
.EqualsIgnoreCaseAscii(sCSS1_url
)) ||
658 (('r'==aToken
.GetChar(0) || 'R'==aToken
.GetChar(0)) &&
659 aToken
.EqualsIgnoreCaseAscii(sCSS1_rgb
)) ) )
662 ::rtl::OUStringBuffer
sTmpBuffer2( 64L );
664 sTmpBuffer2
.append( cNextCh
);
667 case '(': nNestCnt
++; break;
668 case ')': nNestCnt
--; break;
670 cNextCh
= GetNextChar();
671 } while( (nNestCnt
>1 || ')'!=cNextCh
) && !IsEOF() );
672 sTmpBuffer2
.append( cNextCh
);
673 aToken
+= String(sTmpBuffer2
.makeStringAndClear());
675 nRet
= 'u'==aToken
.GetChar(0) || 'U'==aToken
.GetChar(0)
685 // Fehlerbehandlung: Zeichen ignorieren
689 cNextCh
= GetNextChar();
691 } while( CSS1_NULL
==nRet
&& IsParserWorking() );
700 // Dies folegenden Funktionen realisieren den in
702 // http://www.w3.orh/pub/WWW/TR/WD-css1.html
703 // bzw. http://www.w3.orh/pub/WWW/TR/WD-css1-960220.html
705 // beschriebenen Parser fuer CSS1. Es handelt sich um eine direkte
706 // Umsetzung der dort beschriebenen Grammatik
717 void CSS1Parser::ParseStyleSheet()
723 while( !bDone
&& IsParserWorking() )
725 LOOP_CHECK_CHECK( "Endlos-Schleife in ParseStyleSheet()/import *" )
729 case CSS1_IMPORT_SYM
:
731 // url ueberspringen wir ungeprueft
732 nToken
= GetNextToken();
734 case CSS1_IDENT
: // Look-Aheads
737 // /Feature: PrintExt
739 // /Feature: PrintExt
744 // Fehlerbehandlung: ueberlesen
749 nToken
= GetNextToken();
755 while( IsParserWorking() )
757 LOOP_CHECK_CHECK( "Endlos-Schleife in ParseStyleSheet()/rule *" )
761 case CSS1_IDENT
: // Look-Aheads
764 // /Feature: PrintExt
766 // /Feature: PrintExt
771 // Fehlerbehandlung: ueberlesen
772 nToken
= GetNextToken();
779 // : selector [ ',' selector ]*
780 // '{' declaration [ ';' declaration ]* '}'
782 void CSS1Parser::ParseRule()
785 CSS1Selector
*pSelector
= ParseSelector();
789 // Selektor verarbeiten
790 if( SelectorParsed( pSelector
, TRUE
) )
796 while( CSS1_COMMA
==nToken
&& IsParserWorking() )
798 LOOP_CHECK_CHECK( "Endlos-Schleife in ParseRule()/selector *" )
801 nToken
= GetNextToken();
804 pSelector
= ParseSelector();
808 // Selektor verarbeiten
809 if( SelectorParsed( pSelector
, FALSE
) )
814 if( CSS1_OBRACE
!= nToken
)
816 nToken
= GetNextToken();
820 CSS1Expression
*pExpr
= ParseDeclaration( aProperty
);
824 // expression verarbeiten
825 if( DeclarationParsed( aProperty
, pExpr
) )
830 // [ ';' declaration ]*
831 while( CSS1_SEMICOLON
==nToken
&& IsParserWorking() )
833 LOOP_CHECK_CHECK( "Endlos-Schleife in ParseRule()/declaration *" )
836 nToken
= GetNextToken();
839 if( CSS1_IDENT
== nToken
)
841 CSS1Expression
*pExp
= ParseDeclaration( aProperty
);
844 // expression verarbeiten
845 if( DeclarationParsed( aProperty
, pExp
) )
852 if( CSS1_CBRACE
== nToken
)
853 nToken
= GetNextToken();
857 // : simple_selector+ [ ':' pseudo_element ]?
860 // : element_name [ DOT_WO_WS class ]?
876 CSS1Selector
*CSS1Parser::ParseSelector()
878 CSS1Selector
*pRoot
= 0, *pLast
= 0;
881 CSS1Selector
*pNew
= 0;
886 while( !bDone
&& IsParserWorking() )
888 LOOP_CHECK_CHECK( "Endlos-Schleife in ParseSelector()" )
890 BOOL bNextToken
= TRUE
;
896 // element_name [ DOT_WO_WS class ]?
899 String aElement
= aToken
;
900 CSS1SelectorType eType
= CSS1_SELTYPE_ELEMENT
;
901 nToken
= GetNextToken();
903 if( CSS1_DOT_WO_WS
== nToken
)
906 nToken
= GetNextToken();
909 if( CSS1_IDENT
== nToken
)
911 (aElement
+= '.') += aToken
;
912 eType
= CSS1_SELTYPE_ELEM_CLASS
;
922 // das war jetzt ein Look-Ahead
925 pNew
= new CSS1Selector( eType
, aElement
);
932 nToken
= GetNextToken();
934 if( CSS1_IDENT
==nToken
)
937 pNew
= new CSS1Selector( CSS1_SELTYPE_CLASS
, aToken
);
949 nToken
= GetNextToken();
951 if( CSS1_IDENT
==nToken
)
954 pNew
= new CSS1Selector( CSS1_SELTYPE_ID
, aToken
);
963 // /Feature: PrintExt
967 pNew
= new CSS1Selector( CSS1_SELTYPE_PAGE
, aToken
);
970 // /Feature: PrintExt
973 // wir wissen nicht was kommt, also aufhoehren
978 // falls ein Selektor angelegt wurd, ihn speichern
981 DBG_ASSERT( (pRoot
!=0) == (pLast
!=0),
982 "Root-Selektor, aber kein Last" );
984 pLast
->SetNext( pNew
);
992 if( bNextToken
&& !bDone
)
993 nToken
= GetNextToken();
998 // simple_selector fehlt
1002 // [ ':' pseudo_element ]?
1003 if( CSS1_COLON
==nToken
&& IsParserWorking() )
1005 // ':' pseudo element
1006 nToken
= GetNextToken();
1007 if( CSS1_IDENT
==nToken
)
1009 pLast
->SetNext( new CSS1Selector(CSS1_SELTYPE_PSEUDO
,aToken
) );
1010 nToken
= GetNextToken();
1014 // pseudo_element fehlt
1023 // : property ':' expr prio?
1027 // : term [ operator term ]*
1030 // : unary_operator?
1031 // [ NUMBER | STRING | PERCENTAGE | LENGTH | EMS | EXS | IDENT |
1032 // HEXCOLOR | URL | RGB ]
1035 // : '/' | ',' | /* empty */
1043 // das Vorzeichen wird nur fuer numerische Werte (ausser PERCENTAGE)
1044 // beruecksichtigt und wird auf nValue angewendet!
1045 CSS1Expression
*CSS1Parser::ParseDeclaration( String
& rProperty
)
1047 CSS1Expression
*pRoot
= 0, *pLast
= 0;
1050 if( CSS1_IDENT
!= nToken
)
1057 nToken
= GetNextToken();
1061 if( CSS1_COLON
!= nToken
)
1066 nToken
= GetNextToken();
1068 // term [operator term]*
1069 // hier sind wir sehr lax, was die Syntax angeht, sollte aber kein
1072 sal_Unicode cSign
= 0, cOp
= 0;
1073 CSS1Expression
*pNew
= 0;
1077 while( !bDone
&& IsParserWorking() )
1079 LOOP_CHECK_CHECK( "Endlos-Schleife in ParseDeclaration()" )
1093 case CSS1_PIXLENGTH
:
1099 case CSS1_PERCENTAGE
:
1104 pNew
= new CSS1Expression( nToken
, aToken
, nValue
, cOp
);
1105 nValue
= 0; // sonst landet das auch im naechsten Ident
1125 // falls ein Expression angelegt wurde, diesen speichern
1128 DBG_ASSERT( (pRoot
!=0) == (pLast
!=0),
1129 "Root-Selektor, aber kein Last" );
1131 pLast
->SetNext( pNew
);
1140 nToken
= GetNextToken();
1150 if( CSS1_IMPORTANT_SYM
==nToken
)
1153 nToken
= GetNextToken();
1161 CSS1Parser::CSS1Parser()
1165 CSS1Parser::~CSS1Parser()
1171 BOOL
CSS1Parser::ParseStyleSheet( const String
& rIn
)
1176 while( aTmp
.Len() &&
1177 ( ' '==(c
=aTmp
.GetChar(0)) || '\t'==c
|| '\r'==c
|| '\n'==c
) )
1180 while( aTmp
.Len() && ( ' '==(c
=aTmp
.GetChar( aTmp
.Len()-1))
1181 || '\t'==c
|| '\r'==c
|| '\n'==c
) )
1182 aTmp
.Erase( aTmp
.Len()-1 );
1184 // SGML-Kommentare entfernen
1185 if( aTmp
.Len() >= 4 &&
1186 aTmp
.CompareToAscii("<!--",4) == COMPARE_EQUAL
)
1189 if( aTmp
.Len() >=3 &&
1190 aTmp
.Copy(aTmp
.Len()-3).CompareToAscii("-->") == COMPARE_EQUAL
)
1191 aTmp
.Erase( aTmp
.Len()-3 );
1204 BOOL
CSS1Parser::ParseStyleOption( const String
& rIn
)
1212 CSS1Expression
*pExpr
= ParseDeclaration( aProperty
);
1218 // expression verarbeiten
1219 if( DeclarationParsed( aProperty
, pExpr
) )
1224 // [ ';' declaration ]*
1225 while( CSS1_SEMICOLON
==nToken
&& IsParserWorking() )
1227 LOOP_CHECK_CHECK( "Endlos-Schleife in ParseStyleOption()" )
1229 nToken
= GetNextToken();
1230 if( CSS1_IDENT
==nToken
)
1232 CSS1Expression
*pExp
= ParseDeclaration( aProperty
);
1235 // expression verarbeiten
1236 if( DeclarationParsed( aProperty
, pExp
) )
1245 BOOL
CSS1Parser::SelectorParsed( const CSS1Selector
* /* pSelector */, BOOL
/*bFirst*/ )
1247 // Selektor loeschen
1251 BOOL
CSS1Parser::DeclarationParsed( const String
& /*rProperty*/,
1252 const CSS1Expression
* /* pExpr */ )
1254 // Deklaration loeschen
1261 CSS1Selector::~CSS1Selector()
1268 CSS1Expression::~CSS1Expression()
1273 BOOL
CSS1Expression::GetURL( String
& rURL
) const
1275 DBG_ASSERT( CSS1_URL
==eType
, "CSS1-Ausruck ist keine Farbe URL" );
1277 DBG_ASSERT( aValue
.CompareIgnoreCaseToAscii( sCSS1_url
, 3 ) ==
1280 '(' == aValue
.GetChar(3) &&
1281 ')' == aValue
.GetChar(aValue
.Len()-1),
1282 "keine gueltiges URL(...)" );
1286 if( aValue
.Len() > 5 )
1288 rURL
= aValue
.Copy( 4, aValue
.Len()-5 );
1289 rURL
.EraseTrailingChars();
1290 rURL
.EraseLeadingChars();
1297 BOOL
CSS1Expression::GetColor( Color
&rColor
) const
1299 DBG_ASSERT( CSS1_IDENT
==eType
|| CSS1_RGB
==eType
||
1300 CSS1_HEXCOLOR
==eType
|| CSS1_STRING
==eType
,
1301 "CSS1-Ausruck kann keine Farbe sein" );
1304 ULONG nColor
= ULONG_MAX
;
1310 BYTE aColors
[3] = { 0, 0, 0 };
1312 DBG_ASSERT( aValue
.CompareIgnoreCaseToAscii( sCSS1_rgb
, 3 )
1315 '(' == aValue
.GetChar( 3 ) &&
1316 ')' == aValue
.GetChar( aValue
.Len()-1),
1317 "keine gueltiges RGB(...)" );
1319 String
aColorStr( aValue
.Copy( 4, aValue
.Len()-1 ) );
1321 xub_StrLen nPos
= 0;
1324 while( nCol
< 3 && nPos
< aColorStr
.Len() )
1327 while( nPos
< aColorStr
.Len() &&
1328 ((c
=aColorStr
.GetChar(nPos
)) == ' ' || c
== '\t' ||
1329 c
== '\n' || c
== '\r' ) )
1332 xub_StrLen nEnd
= aColorStr
.Search( ',', nPos
);
1334 if( STRING_NOTFOUND
==nEnd
)
1336 aNumber
= aColorStr
.Copy(nPos
);
1337 nPos
= aColorStr
.Len();
1341 aNumber
= aColorStr
.Copy( nPos
, nEnd
-nPos
);
1345 USHORT nNumber
= (USHORT
)aNumber
.ToInt32();
1346 if( aNumber
.Search('%') != STRING_NOTFOUND
)
1353 else if( nNumber
> 255 )
1356 aColors
[nCol
] = (BYTE
)nNumber
;
1360 rColor
.SetRed( aColors
[0] );
1361 rColor
.SetGreen( aColors
[1] );
1362 rColor
.SetBlue( aColors
[2] );
1364 bRet
= TRUE
; // etwas anderes als eine Farbe kann es nicht sein
1371 String
aTmp( aValue
);
1372 aTmp
.ToUpperAscii();
1373 nColor
= GetHTMLColor( aTmp
);
1374 bRet
= nColor
!= ULONG_MAX
;
1376 if( bRet
|| CSS1_STRING
!= eType
|| !aValue
.Len() ||
1377 aValue
.GetChar( 0 )!='#' )
1382 // HACK fuer MS-IE: DIe Farbe kann auch in einem String stehen
1383 xub_StrLen nOffset
= CSS1_STRING
==eType
? 1 : 0;
1384 BOOL bDouble
= aValue
.Len()-nOffset
== 3;
1385 xub_StrLen i
= nOffset
, nEnd
= (bDouble
? 3 : 6) + nOffset
;
1388 for( ; i
<nEnd
; i
++ )
1390 sal_Unicode c
= (i
<aValue
.Len() ? aValue
.GetChar(i
)
1392 if( c
>= '0' && c
<= '9' )
1394 else if( c
>= 'A' && c
<= 'F' )
1396 else if( c
>= 'a' && c
<= 'f' )
1420 if( bRet
&& nColor
!=ULONG_MAX
)
1422 rColor
.SetRed( (BYTE
)((nColor
& 0x00ff0000UL
) >> 16) );
1423 rColor
.SetGreen( (BYTE
)((nColor
& 0x0000ff00UL
) >> 8) );
1424 rColor
.SetBlue( (BYTE
)(nColor
& 0x000000ffUL
) );