1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
23 #include <rtl/ustrbuf.hxx>
24 #include <vcl/svapp.hxx>
25 #include <svtools/htmltokn.h>
26 #include <comphelper/string.hxx>
27 #include "css1kywd.hxx"
28 #include "parcss1.hxx"
30 // Loop-Check: Um Endlos-Schleifen zu vermeiden, wird in jeder
31 // Schalife geprueft, ob ein Fortschritt in der Eingabe-Position
37 #define LOOP_CHECK_DECL \
38 sal_Int32 nOldInPos = SAL_MAX_INT32;
39 #define LOOP_CHECK_RESTART \
40 nOldInPos = SAL_MAX_INT32;
41 #define LOOP_CHECK_CHECK( where ) \
42 OSL_ENSURE( nOldInPos!=nInPos || cNextCh==(sal_Unicode)EOF, where ); \
43 if( nOldInPos==nInPos && cNextCh!=(sal_Unicode)EOF ) \
50 #define LOOP_CHECK_DECL
51 #define LOOP_CHECK_RESTART
52 #define LOOP_CHECK_CHECK( where )
56 const sal_Int32 MAX_LEN
= 1024;
58 void CSS1Parser::InitRead( const OUString
& rIn
)
63 bWhiteSpace
= true; // Wenn noch nichts gelesen wurde ist das wie WS
65 eState
= CSS1_PAR_WORKING
;
70 cNextCh
= GetNextChar();
71 nToken
= GetNextToken();
74 sal_Unicode
CSS1Parser::GetNextChar()
76 if( nInPos
>= aIn
.getLength() )
79 return (sal_Unicode
)EOF
;
82 sal_Unicode c
= aIn
[nInPos
];
96 // Diese Funktion realisiert den in
98 // http://www.w3.orh/pub/WWW/TR/WD-css1.html
99 // bzw. http://www.w3.orh/pub/WWW/TR/WD-css1-960220.html
101 // beschriebenen Scanner fuer CSS1. Es handelt sich um eine direkte
102 // Umsetzung der dort beschriebenen Lex-Grammatik
104 CSS1Token
CSS1Parser::GetNextToken()
106 CSS1Token nRet
= CSS1_NULL
;
110 // Merken, ob davor White-Space gelesen wurde
111 bool bPrevWhiteSpace
= bWhiteSpace
;
117 case '/': // COMMENT | '/'
119 cNextCh
= GetNextChar();
123 cNextCh
= GetNextChar();
125 bool bAsterisk
= false;
126 while( !(bAsterisk
&& '/'==cNextCh
) && !IsEOF() )
128 bAsterisk
= ('*'==cNextCh
);
129 cNextCh
= GetNextChar();
141 case '@': // '@import' | '@XXX'
143 cNextCh
= GetNextChar();
144 if (rtl::isAsciiAlpha(cNextCh
))
146 // den naechsten Identifer scannen
147 OUStringBuffer
sTmpBuffer(32);
149 sTmpBuffer
.append( cNextCh
);
150 cNextCh
= GetNextChar();
151 } while( (rtl::isAsciiAlphanumeric(cNextCh
) ||
152 '-' == cNextCh
) && !IsEOF() );
154 aToken
+= sTmpBuffer
.makeStringAndClear();
156 // und schauen, ob wir ihn kennen
161 if( aToken
.equalsIgnoreAsciiCase( "import" ) )
162 nRet
= CSS1_IMPORT_SYM
;
166 if( aToken
.equalsIgnoreAsciiCase( "page" ) )
167 nRet
= CSS1_PAGE_SYM
;
171 // Fehlerbehandlung: '@ident' und alles bis
172 // zu einem Semikolon der dem Ende des folgenden
174 if( CSS1_NULL
==nRet
)
178 sal_Unicode cQuoteCh
= 0;
179 bool bDone
= false, bEscape
= false;
180 while( !bDone
&& !IsEOF() )
182 bool bOldEscape
= bEscape
;
187 if( !cQuoteCh
&& !bOldEscape
)
191 if( !cQuoteCh
&& !bOldEscape
)
192 bDone
= nBlockLvl
==0;
195 if( !cQuoteCh
&& !bOldEscape
)
196 bDone
= --nBlockLvl
==0;
204 if( cQuoteCh
== cNextCh
)
218 cNextCh
= GetNextChar();
227 case '!': // '!' 'legal' | '!' 'important' | syntax error
229 // White Space ueberlesen
230 cNextCh
= GetNextChar();
231 while( ( ' ' == cNextCh
||
232 (cNextCh
>= 0x09 && cNextCh
<= 0x0d) ) && !IsEOF() )
235 cNextCh
= GetNextChar();
238 if( 'i'==cNextCh
|| 'I'==cNextCh
)
240 // den naechsten Identifer scannen
241 OUStringBuffer
sTmpBuffer(32);
243 sTmpBuffer
.append( cNextCh
);
244 cNextCh
= GetNextChar();
245 } while( (rtl::isAsciiAlphanumeric(cNextCh
) ||
246 '-' == cNextCh
) && !IsEOF() );
248 aToken
+= sTmpBuffer
.makeStringAndClear();
250 if( ( 'i'==aToken
[0] || 'I'==aToken
[0] ) &&
251 aToken
.equalsIgnoreAsciiCase( "important" ) )
254 nRet
= CSS1_IMPORTANT_SYM
;
258 // Fehlerbehandlung: '!' ignorieren, IDENT nicht
267 // Fehlerbehandlung: '!' ignorieren
276 // \... geht noch nicht!!!
277 sal_Unicode cQuoteChar
= cNextCh
;
278 cNextCh
= GetNextChar();
280 OUStringBuffer
sTmpBuffer( MAX_LEN
);
282 sTmpBuffer
.append( cNextCh
);
283 cNextCh
= GetNextChar();
284 } while( cQuoteChar
!= cNextCh
&& !IsEOF() );
286 aToken
+= sTmpBuffer
.toString();
301 case '9': // NUMBER | PERCENTAGE | LENGTH
303 // die aktuelle Position retten
304 std::size_t nInPosSave
= nInPos
;
305 sal_Unicode cNextChSave
= cNextCh
;
306 sal_uInt32 nlLineNrSave
= nlLineNr
;
307 sal_uInt32 nlLinePosSave
= nlLinePos
;
308 bool bEOFSave
= bEOF
;
310 // erstmal versuchen eine Hex-Zahl zu scannen
311 OUStringBuffer
sTmpBuffer( 16 );
313 sTmpBuffer
.append( cNextCh
);
314 cNextCh
= GetNextChar();
315 } while( sTmpBuffer
.getLength() < 7 &&
316 ( ('0'<=cNextCh
&& '9'>=cNextCh
) ||
317 ('A'<=cNextCh
&& 'F'>=cNextCh
) ||
318 ('a'<=cNextCh
&& 'f'>=cNextCh
) ) &&
321 if( sTmpBuffer
.getLength()==6 )
323 // wir haben eine hexadezimale Farbe gefunden
324 aToken
+= sTmpBuffer
.makeStringAndClear();
325 nRet
= CSS1_HEXCOLOR
;
331 // sonst versuchen wir es mit einer Zahl
333 cNextCh
= cNextChSave
;
334 nlLineNr
= nlLineNrSave
;
335 nlLinePos
= nlLinePosSave
;
338 // erstmal die Zahl scannen
339 sTmpBuffer
.setLength( 0L );
341 sTmpBuffer
.append( cNextCh
);
342 cNextCh
= GetNextChar();
343 } while( (('0'<=cNextCh
&& '9'>=cNextCh
) || '.'==cNextCh
) &&
346 aToken
+= sTmpBuffer
.makeStringAndClear();
347 nValue
= aToken
.toDouble();
349 // White Space ueberlesen
350 while( ( ' ' == cNextCh
||
351 (cNextCh
>= 0x09 && cNextCh
<= 0x0d) ) && !IsEOF() )
354 cNextCh
= GetNextChar();
357 // und nun Schauen, ob es eine Einheit gibt
360 case '%': // PERCENTAGE
362 nRet
= CSS1_PERCENTAGE
;
366 case 'C': // LENGTH cm | LENGTH IDENT
368 case 'E': // LENGTH (em | ex) | LENGTH IDENT
370 case 'I': // LENGTH inch | LENGTH IDENT
372 case 'P': // LENGTH (pt | px | pc) | LENGTH IDENT
374 case 'M': // LENGTH mm | LENGTH IDENT
376 // die aktuelle Position retten
377 sal_Int32 nInPosOld
= nInPos
;
378 sal_Unicode cNextChOld
= cNextCh
;
379 sal_uLong nlLineNrOld
= nlLineNr
;
380 sal_uLong nlLinePosOld
= nlLinePos
;
383 // den naechsten Identifer scannen
385 OUStringBuffer
sTmpBuffer2(64);
387 sTmpBuffer2
.append( cNextCh
);
388 cNextCh
= GetNextChar();
389 } while( (rtl::isAsciiAlphanumeric(cNextCh
) ||
390 '-' == cNextCh
) && !IsEOF() );
392 aIdent
+= sTmpBuffer2
.makeStringAndClear();
394 // Ist es eine Einheit?
395 const sal_Char
*pCmp1
= nullptr, *pCmp2
= nullptr, *pCmp3
= nullptr;
396 double nScale1
= 1., nScale2
= 1.;
397 CSS1Token nToken1
= CSS1_LENGTH
,
398 nToken2
= CSS1_LENGTH
,
399 nToken3
= CSS1_LENGTH
;
405 nScale1
= (72.*20.)/2.54; // twip
418 nScale1
= 72.*20.; // twip
423 nScale1
= (72.*20.)/25.4; // twip
428 nScale1
= 20.; // twip
431 nScale2
= 12.*20.; // twip
434 nToken3
= CSS1_PIXLENGTH
;
439 OSL_ENSURE( pCmp1
, "Wo kommt das erste Zeichen her?" );
440 if( aIdent
.equalsIgnoreAsciiCaseAscii( pCmp1
) )
446 aIdent
.equalsIgnoreAsciiCaseAscii( pCmp2
) )
452 aIdent
.equalsIgnoreAsciiCaseAscii( pCmp3
) )
454 nScale
= 1.; // nScale3
462 if( CSS1_LENGTH
==nRet
&& nScale
!=1.0 )
465 if( nRet
== CSS1_NUMBER
)
468 cNextCh
= cNextChOld
;
469 nlLineNr
= nlLineNrOld
;
470 nlLinePos
= nlLinePosOld
;
480 default: // NUMBER IDENT
489 // link/visited/active abfangen !!!
493 case '.': // DOT_W_WS | DOT_WO_WS
494 nRet
= bPrevWhiteSpace
? CSS1_DOT_W_WS
: CSS1_DOT_WO_WS
;
514 nRet
= CSS1_SEMICOLON
;
522 cNextCh
= GetNextChar();
523 if( ('0'<=cNextCh
&& '9'>=cNextCh
) ||
524 ('a'<=cNextCh
&& 'f'>=cNextCh
) ||
525 ('A'<=cNextCh
&& 'F'>=cNextCh
) )
527 // die aktuelle Position retten
528 sal_Int32 nInPosSave
= nInPos
;
529 sal_Unicode cNextChSave
= cNextCh
;
530 sal_uLong nlLineNrSave
= nlLineNr
;
531 sal_uLong nlLinePosSave
= nlLinePos
;
532 bool bEOFSave
= bEOF
;
534 // erstmal versuchen eine Hex-Zahl zu scannen
535 OUStringBuffer
sTmpBuffer(6);
537 sTmpBuffer
.append( cNextCh
);
538 cNextCh
= GetNextChar();
539 } while( sTmpBuffer
.getLength() < 7 &&
540 ( ('0'<=cNextCh
&& '9'>=cNextCh
) ||
541 ('A'<=cNextCh
&& 'F'>=cNextCh
) ||
542 ('a'<=cNextCh
&& 'f'>=cNextCh
) ) &&
545 if( sTmpBuffer
.getLength()==6 || sTmpBuffer
.getLength()==3 )
547 // wir haben eine hexadezimale Farbe gefunden
548 aToken
+= sTmpBuffer
.makeStringAndClear();
549 nRet
= CSS1_HEXCOLOR
;
555 // sonst versuchen wir es mit einer Zahl
557 cNextCh
= cNextChSave
;
558 nlLineNr
= nlLineNrSave
;
559 nlLinePos
= nlLinePosSave
;
570 case '\n': // White-Space
574 case (sal_Unicode
)EOF
:
577 eState
= CSS1_PAR_ACCEPTED
;
583 default: // IDENT | syntax error
584 if (rtl::isAsciiAlpha(cNextCh
))
588 bool bHexColor
= true;
590 // den naechsten Identifer scannen
591 OUStringBuffer
sTmpBuffer(64);
593 sTmpBuffer
.append( cNextCh
);
596 bHexColor
= sTmpBuffer
.getLength()<7 &&
597 ( ('0'<=cNextCh
&& '9'>=cNextCh
) ||
598 ('A'<=cNextCh
&& 'F'>=cNextCh
) ||
599 ('a'<=cNextCh
&& 'f'>=cNextCh
) );
601 cNextCh
= GetNextChar();
602 } while( (rtl::isAsciiAlphanumeric(cNextCh
) ||
603 '-' == cNextCh
) && !IsEOF() );
605 aToken
+= sTmpBuffer
.makeStringAndClear();
607 if( bHexColor
&& sTmpBuffer
.getLength()==6 )
610 nRet
= CSS1_HEXCOLOR
;
615 ( (('u'==aToken
[0] || 'U'==aToken
[0]) &&
616 aToken
.equalsIgnoreAsciiCase( "url" )) ||
617 (('r'==aToken
[0] || 'R'==aToken
[0]) &&
618 aToken
.equalsIgnoreAsciiCase( "rgb" )) ) )
621 OUStringBuffer
sTmpBuffer2(64);
623 sTmpBuffer2
.append( cNextCh
);
626 case '(': nNestCnt
++; break;
627 case ')': nNestCnt
--; break;
629 cNextCh
= GetNextChar();
630 } while( (nNestCnt
>1 || ')'!=cNextCh
) && !IsEOF() );
631 sTmpBuffer2
.append( cNextCh
);
632 aToken
+= sTmpBuffer2
.makeStringAndClear();
634 nRet
= 'u'==aToken
[0] || 'U'==aToken
[0]
644 // Fehlerbehandlung: Zeichen ignorieren
648 cNextCh
= GetNextChar();
650 } while( CSS1_NULL
==nRet
&& IsParserWorking() );
655 // Dies folegenden Funktionen realisieren den in
657 // http://www.w3.orh/pub/WWW/TR/WD-css1.html
658 // bzw. http://www.w3.orh/pub/WWW/TR/WD-css1-960220.html
660 // beschriebenen Parser fuer CSS1. Es handelt sich um eine direkte
661 // Umsetzung der dort beschriebenen Grammatik
672 void CSS1Parser::ParseStyleSheet()
678 while( !bDone
&& IsParserWorking() )
680 LOOP_CHECK_CHECK( "Endlos-Schleife in ParseStyleSheet()/import *" )
684 case CSS1_IMPORT_SYM
:
686 // url ueberspringen wir ungeprueft
687 nToken
= GetNextToken();
689 case CSS1_IDENT
: // Look-Aheads
697 // Fehlerbehandlung: ueberlesen
702 nToken
= GetNextToken();
708 while( IsParserWorking() )
710 LOOP_CHECK_CHECK( "Endlos-Schleife in ParseStyleSheet()/rule *" )
714 case CSS1_IDENT
: // Look-Aheads
722 // Fehlerbehandlung: ueberlesen
723 nToken
= GetNextToken();
730 // : selector [ ',' selector ]*
731 // '{' declaration [ ';' declaration ]* '}'
733 void CSS1Parser::ParseRule()
736 CSS1Selector
*pSelector
= ParseSelector();
740 // Selektor verarbeiten
741 if( SelectorParsed( pSelector
, true ) )
747 while( CSS1_COMMA
==nToken
&& IsParserWorking() )
749 LOOP_CHECK_CHECK( "Endlos-Schleife in ParseRule()/selector *" )
752 nToken
= GetNextToken();
755 pSelector
= ParseSelector();
759 // Selektor verarbeiten
760 if( SelectorParsed( pSelector
, false ) )
765 if( CSS1_OBRACE
!= nToken
)
767 nToken
= GetNextToken();
771 CSS1Expression
*pExpr
= ParseDeclaration( aProperty
);
775 // expression verarbeiten
776 if( DeclarationParsed( aProperty
, pExpr
) )
781 // [ ';' declaration ]*
782 while( CSS1_SEMICOLON
==nToken
&& IsParserWorking() )
784 LOOP_CHECK_CHECK( "Endlos-Schleife in ParseRule()/declaration *" )
787 nToken
= GetNextToken();
790 if( CSS1_IDENT
== nToken
)
792 CSS1Expression
*pExp
= ParseDeclaration( aProperty
);
795 // expression verarbeiten
796 if( DeclarationParsed( aProperty
, pExp
) )
803 if( CSS1_CBRACE
== nToken
)
804 nToken
= GetNextToken();
808 // : simple_selector+ [ ':' pseudo_element ]?
811 // : element_name [ DOT_WO_WS class ]?
827 CSS1Selector
*CSS1Parser::ParseSelector()
829 CSS1Selector
*pRoot
= nullptr, *pLast
= nullptr;
832 CSS1Selector
*pNew
= nullptr;
837 while( !bDone
&& IsParserWorking() )
839 LOOP_CHECK_CHECK( "Endlos-Schleife in ParseSelector()" )
841 bool bNextToken
= true;
847 // element_name [ DOT_WO_WS class ]?
850 OUString aElement
= aToken
;
851 CSS1SelectorType eType
= CSS1_SELTYPE_ELEMENT
;
852 nToken
= GetNextToken();
854 if( CSS1_DOT_WO_WS
== nToken
)
857 nToken
= GetNextToken();
860 if( CSS1_IDENT
== nToken
)
862 aElement
+= "." + aToken
;
863 eType
= CSS1_SELTYPE_ELEM_CLASS
;
873 // das war jetzt ein Look-Ahead
876 pNew
= new CSS1Selector( eType
, aElement
);
883 nToken
= GetNextToken();
885 if( CSS1_IDENT
==nToken
)
888 pNew
= new CSS1Selector( CSS1_SELTYPE_CLASS
, aToken
);
900 nToken
= GetNextToken();
902 if( CSS1_IDENT
==nToken
)
905 pNew
= new CSS1Selector( CSS1_SELTYPE_ID
, aToken
);
917 pNew
= new CSS1Selector( CSS1_SELTYPE_PAGE
, aToken
);
922 // wir wissen nicht was kommt, also aufhoehren
927 // falls ein Selektor angelegt wurd, ihn speichern
930 OSL_ENSURE( (pRoot
!=nullptr) == (pLast
!=nullptr),
931 "Root-Selektor, aber kein Last" );
933 pLast
->SetNext( pNew
);
941 if( bNextToken
&& !bDone
)
942 nToken
= GetNextToken();
947 // simple_selector fehlt
951 // [ ':' pseudo_element ]?
952 if( CSS1_COLON
==nToken
&& IsParserWorking() )
954 // ':' pseudo element
955 nToken
= GetNextToken();
956 if( CSS1_IDENT
==nToken
)
958 pLast
->SetNext( new CSS1Selector(CSS1_SELTYPE_PSEUDO
,aToken
) );
959 nToken
= GetNextToken();
963 // pseudo_element fehlt
972 // : property ':' expr prio?
976 // : term [ operator term ]*
980 // [ NUMBER | STRING | PERCENTAGE | LENGTH | EMS | EXS | IDENT |
981 // HEXCOLOR | URL | RGB ]
984 // : '/' | ',' | /* empty */
992 // das Vorzeichen wird nur fuer numerische Werte (ausser PERCENTAGE)
993 // beruecksichtigt und wird auf nValue angewendet!
994 CSS1Expression
*CSS1Parser::ParseDeclaration( OUString
& rProperty
)
996 CSS1Expression
*pRoot
= nullptr, *pLast
= nullptr;
999 if( CSS1_IDENT
!= nToken
)
1006 nToken
= GetNextToken();
1009 if( CSS1_COLON
!= nToken
)
1014 nToken
= GetNextToken();
1016 // term [operator term]*
1017 // hier sind wir sehr lax, was die Syntax angeht, sollte aber kein
1020 sal_Unicode cSign
= 0, cOp
= 0;
1021 CSS1Expression
*pNew
= nullptr;
1025 while( !bDone
&& IsParserWorking() )
1027 LOOP_CHECK_CHECK( "Endlos-Schleife in ParseDeclaration()" )
1041 case CSS1_PIXLENGTH
:
1048 case CSS1_PERCENTAGE
:
1053 pNew
= new CSS1Expression( nToken
, aToken
, nValue
, cOp
);
1054 nValue
= 0; // sonst landet das auch im naechsten Ident
1074 // falls ein Expression angelegt wurde, diesen speichern
1077 OSL_ENSURE( (pRoot
!=nullptr) == (pLast
!=nullptr),
1078 "Root-Selektor, aber kein Last" );
1080 pLast
->SetNext( pNew
);
1089 nToken
= GetNextToken();
1099 if( CSS1_IMPORTANT_SYM
==nToken
)
1102 nToken
= GetNextToken();
1108 CSS1Parser::CSS1Parser()
1109 : bWhiteSpace(false)
1116 , eState(CSS1_PAR_ACCEPTED
)
1121 CSS1Parser::~CSS1Parser()
1125 bool CSS1Parser::ParseStyleSheet( const OUString
& rIn
)
1127 OUString
aTmp( rIn
);
1130 while( !aTmp
.isEmpty() &&
1131 ( ' '==(c
=aTmp
[0]) || '\t'==c
|| '\r'==c
|| '\n'==c
) )
1132 aTmp
= aTmp
.copy( 1, aTmp
.getLength() - 1 );
1134 while( !aTmp
.isEmpty() && ( ' '==(c
=aTmp
[aTmp
.getLength()-1])
1135 || '\t'==c
|| '\r'==c
|| '\n'==c
) )
1136 aTmp
= aTmp
.copy( 0, aTmp
.getLength()-1 );
1138 // SGML-Kommentare entfernen
1139 if( aTmp
.getLength() >= 4 &&
1140 aTmp
.startsWith( "<!--" ) )
1141 aTmp
= aTmp
.copy( 4, aTmp
.getLength() - 4 );
1143 if( aTmp
.getLength() >=3 &&
1144 aTmp
.endsWith("-->") )
1145 aTmp
= aTmp
.copy( 0, aTmp
.getLength() - 3 );
1147 if( aTmp
.isEmpty() )
1157 bool CSS1Parser::ParseStyleOption( const OUString
& rIn
)
1164 // fdo#41796: skip over spurious semicolons
1165 while (CSS1_SEMICOLON
== nToken
)
1167 nToken
= GetNextToken();
1171 CSS1Expression
*pExpr
= ParseDeclaration( aProperty
);
1177 // expression verarbeiten
1178 if( DeclarationParsed( aProperty
, pExpr
) )
1183 // [ ';' declaration ]*
1184 while( CSS1_SEMICOLON
==nToken
&& IsParserWorking() )
1186 LOOP_CHECK_CHECK( "Endlos-Schleife in ParseStyleOption()" )
1188 nToken
= GetNextToken();
1189 if( CSS1_IDENT
==nToken
)
1191 CSS1Expression
*pExp
= ParseDeclaration( aProperty
);
1194 // expression verarbeiten
1195 if( DeclarationParsed( aProperty
, pExp
) )
1204 bool CSS1Parser::SelectorParsed( CSS1Selector
* /* pSelector */, bool /*bFirst*/ )
1206 // Selektor loeschen
1210 bool CSS1Parser::DeclarationParsed( const OUString
& /*rProperty*/,
1211 const CSS1Expression
* /* pExpr */ )
1213 // Deklaration loeschen
1217 CSS1Selector::~CSS1Selector()
1222 CSS1Expression::~CSS1Expression()
1227 void CSS1Expression::GetURL( OUString
& rURL
) const
1229 OSL_ENSURE( CSS1_URL
==eType
, "CSS1-Ausruck ist keine Farbe URL" );
1231 OSL_ENSURE( aValue
.startsWithIgnoreAsciiCase( "url" ) &&
1232 aValue
.getLength() > 5 &&
1234 ')' == aValue
[aValue
.getLength()-1],
1235 "keine gueltiges URL(...)" );
1237 if( aValue
.getLength() > 5 )
1239 rURL
= aValue
.copy( 4, aValue
.getLength() - 5 );
1241 // tdf#94088 original stripped only spaces, but there may also be
1242 // double quotes in CSS style URLs, so be prepared to spaces followed
1243 // by a single quote followed by spaces
1244 const sal_Unicode
aSpace(' ');
1245 const sal_Unicode
aSingleQuote('\'');
1247 rURL
= comphelper::string::strip(rURL
, aSpace
);
1248 rURL
= comphelper::string::strip(rURL
, aSingleQuote
);
1249 rURL
= comphelper::string::strip(rURL
, aSpace
);
1253 bool CSS1Expression::GetColor( Color
&rColor
) const
1255 OSL_ENSURE( CSS1_IDENT
==eType
|| CSS1_RGB
==eType
||
1256 CSS1_HEXCOLOR
==eType
|| CSS1_STRING
==eType
,
1257 "CSS1-Ausruck kann keine Farbe sein" );
1260 sal_uInt32 nColor
= SAL_MAX_UINT32
;
1266 sal_uInt8 aColors
[3] = { 0, 0, 0 };
1268 if (!aValue
.startsWithIgnoreAsciiCase( "rgb" ) || aValue
.getLength() < 6 ||
1269 aValue
[3] != '(' || aValue
[aValue
.getLength()-1] != ')')
1274 sal_Int32 nPos
= 4; // start after "rgb("
1275 for ( int nCol
= 0; nCol
< 3 && nPos
> 0; ++nCol
)
1277 const OUString aNumber
= aValue
.getToken(0, ',', nPos
);
1279 sal_Int32 nNumber
= aNumber
.toInt32();
1284 else if( aNumber
.indexOf('%') >= 0 )
1291 else if( nNumber
> 255 )
1294 aColors
[nCol
] = static_cast<sal_uInt8
>(nNumber
);
1297 rColor
.SetRed( aColors
[0] );
1298 rColor
.SetGreen( aColors
[1] );
1299 rColor
.SetBlue( aColors
[2] );
1301 bRet
= true; // etwas anderes als eine Farbe kann es nicht sein
1308 OUString
aTmp( aValue
.toAsciiUpperCase() );
1309 nColor
= GetHTMLColor( aTmp
);
1310 bRet
= nColor
!= SAL_MAX_UINT32
;
1312 if( bRet
|| CSS1_STRING
!= eType
|| aValue
.isEmpty() ||
1318 // HACK fuer MS-IE: DIe Farbe kann auch in einem String stehen
1319 sal_Int32 nOffset
= CSS1_STRING
==eType
? 1 : 0;
1320 bool bDouble
= aValue
.getLength()-nOffset
== 3;
1321 sal_Int32 i
= nOffset
, nEnd
= (bDouble
? 3 : 6) + nOffset
;
1324 for( ; i
<nEnd
; i
++ )
1326 sal_Unicode c
= (i
<aValue
.getLength() ? aValue
[i
]
1328 if( c
>= '0' && c
<= '9' )
1330 else if( c
>= 'A' && c
<= 'F' )
1332 else if( c
>= 'a' && c
<= 'f' )
1354 if( bRet
&& nColor
!=SAL_MAX_UINT32
)
1356 rColor
.SetRed( (sal_uInt8
)((nColor
& 0x00ff0000UL
) >> 16) );
1357 rColor
.SetGreen( (sal_uInt8
)((nColor
& 0x0000ff00UL
) >> 8) );
1358 rColor
.SetBlue( (sal_uInt8
)(nColor
& 0x000000ffUL
) );
1364 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */