1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "xfa/src/foxitlib.h"
8 #include "fde_csssyntax.h"
9 #include "fde_cssdatatable.h"
10 #include "fde_cssstylesheet.h"
LoadHTMLStandardStyleSheet()11 IFDE_CSSStyleSheet* IFDE_CSSStyleSheet::LoadHTMLStandardStyleSheet() {
12 static const FX_WCHAR* s_pStyle =
13 L"html,address,blockquote,body,dd,div,dl,dt,fieldset,form,frame,frameset,"
14 L"h1,h2,h3,h4,h5,h6,noframes,ol,p,ul,center,dir,hr,menu,pre{display:"
15 L"block}"
16 L"li{display:list-item}head{display:none}table{display:table}tr{display:"
17 L"table-row}thead{display:table-header-group}tbody{display:table-row-"
18 L"group}tfoot{display:table-footer-group}"
19 L"col{display:table-column}colgroup{display:table-column-group}td,th{"
20 L"display:table-cell}caption{display:table-caption}th{font-weight:bolder;"
21 L"text-align:center}caption{text-align:center}"
22 L"body{margin:0}h1{font-size:2em;margin:.67em "
23 L"0}h2{font-size:1.5em;margin:.75em 0}h3{font-size:1.17em;margin:.83em "
24 L"0}h4,p,blockquote,ul,fieldset,form,ol,dl,dir,menu{margin:1.12em 0}"
25 L"h5{font-size:.83em;margin:1.5em 0}h6{font-size:.75em;margin:1.67em "
26 L"0}h1,h2,h3,h4,h5,h6,b,strong{font-weight:bolder}blockquote{margin-left:"
27 L"40px;margin-right:40px}i,cite,em,var,address{font-style:italic}"
28 L"pre,tt,code,kbd,samp{font-family:monospace}pre{white-space:pre}button,"
29 L"textarea,input,select{display:inline-block}big{font-size:1.17em}small,"
30 L"sub,sup{font-size:.83em}sub{vertical-align:sub}"
31 L"sup{vertical-align:super}table{border-spacing:2px}thead,tbody,tfoot{"
32 L"vertical-align:middle}td,th,tr{vertical-align:inherit}s,strike,del{"
33 L"text-decoration:line-through}hr{border:1px inset silver}"
34 L"ol,ul,dir,menu,dd{margin-left:40px}ol{list-style-type:decimal}ol ul,ul "
35 L"ol,ul ul,ol "
36 L"ol{margin-top:0;margin-bottom:0}u,ins{text-decoration:underline}center{"
37 L"text-align:center}"
38 L"ruby{display:ruby}rt{display:ruby-text;font-size:.5em}rb{display:ruby-"
39 L"base}rbc{display:ruby-base-group}rtc{display:ruby-text-group}"
40 L"q:before{content:open-quote}q:after{content:close-quote}"
41 L"rp{display:none}";
42 return IFDE_CSSStyleSheet::LoadFromBuffer(
43 CFX_WideString(), s_pStyle, FXSYS_wcslen(s_pStyle), FX_CODEPAGE_UTF8);
44 }
LoadFromStream(const CFX_WideString & szUrl,IFX_Stream * pStream,FX_WORD wCodePage,FX_DWORD dwMediaList)45 IFDE_CSSStyleSheet* IFDE_CSSStyleSheet::LoadFromStream(
46 const CFX_WideString& szUrl,
47 IFX_Stream* pStream,
48 FX_WORD wCodePage,
49 FX_DWORD dwMediaList) {
50 CFDE_CSSStyleSheet* pStyleSheet = new CFDE_CSSStyleSheet(dwMediaList);
51 if (!pStyleSheet->LoadFromStream(szUrl, pStream, wCodePage)) {
52 pStyleSheet->Release();
53 pStyleSheet = NULL;
54 }
55 return pStyleSheet;
56 }
LoadFromBuffer(const CFX_WideString & szUrl,const FX_WCHAR * pBuffer,int32_t iBufSize,FX_WORD wCodePage,FX_DWORD dwMediaList)57 IFDE_CSSStyleSheet* IFDE_CSSStyleSheet::LoadFromBuffer(
58 const CFX_WideString& szUrl,
59 const FX_WCHAR* pBuffer,
60 int32_t iBufSize,
61 FX_WORD wCodePage,
62 FX_DWORD dwMediaList) {
63 CFDE_CSSStyleSheet* pStyleSheet = new CFDE_CSSStyleSheet(dwMediaList);
64 if (!pStyleSheet->LoadFromBuffer(szUrl, pBuffer, iBufSize, wCodePage)) {
65 pStyleSheet->Release();
66 pStyleSheet = NULL;
67 }
68 return pStyleSheet;
69 }
CFDE_CSSStyleSheet(FX_DWORD dwMediaList)70 CFDE_CSSStyleSheet::CFDE_CSSStyleSheet(FX_DWORD dwMediaList)
71 : m_wCodePage(FX_CODEPAGE_UTF8),
72 m_wRefCount(1),
73 m_dwMediaList(dwMediaList),
74 m_pAllocator(NULL) {
75 FXSYS_assert(m_dwMediaList > 0);
76 }
~CFDE_CSSStyleSheet()77 CFDE_CSSStyleSheet::~CFDE_CSSStyleSheet() {
78 Reset();
79 }
Reset()80 void CFDE_CSSStyleSheet::Reset() {
81 for (int32_t i = m_RuleArray.GetSize() - 1; i >= 0; --i) {
82 IFDE_CSSRule* pRule = m_RuleArray.GetAt(i);
83 switch (pRule->GetType()) {
84 case FDE_CSSRULETYPE_Style:
85 ((CFDE_CSSStyleRule*)pRule)->~CFDE_CSSStyleRule();
86 break;
87 case FDE_CSSRULETYPE_Media:
88 ((CFDE_CSSMediaRule*)pRule)->~CFDE_CSSMediaRule();
89 break;
90 case FDE_CSSRULETYPE_FontFace:
91 ((CFDE_CSSFontFaceRule*)pRule)->~CFDE_CSSFontFaceRule();
92 break;
93 default:
94 FXSYS_assert(FALSE);
95 break;
96 }
97 }
98 m_RuleArray.RemoveAll();
99 m_Selectors.RemoveAll();
100 m_StringCache.RemoveAll();
101 if (m_pAllocator) {
102 m_pAllocator->Release();
103 m_pAllocator = NULL;
104 }
105 }
AddRef()106 FX_DWORD CFDE_CSSStyleSheet::AddRef() {
107 return ++m_wRefCount;
108 }
Release()109 FX_DWORD CFDE_CSSStyleSheet::Release() {
110 FX_DWORD dwRefCount = --m_wRefCount;
111 if (dwRefCount == 0) {
112 delete this;
113 }
114 return dwRefCount;
115 }
CountRules() const116 int32_t CFDE_CSSStyleSheet::CountRules() const {
117 return m_RuleArray.GetSize();
118 }
GetRule(int32_t index)119 IFDE_CSSRule* CFDE_CSSStyleSheet::GetRule(int32_t index) {
120 return m_RuleArray.GetAt(index);
121 }
LoadFromStream(const CFX_WideString & szUrl,IFX_Stream * pStream,FX_WORD wCodePage)122 FX_BOOL CFDE_CSSStyleSheet::LoadFromStream(const CFX_WideString& szUrl,
123 IFX_Stream* pStream,
124 FX_WORD wCodePage) {
125 FXSYS_assert(pStream != NULL);
126 IFDE_CSSSyntaxParser* pSyntax = IFDE_CSSSyntaxParser::Create();
127 if (pSyntax == NULL) {
128 return FALSE;
129 }
130 if (pStream->GetCodePage() != wCodePage) {
131 pStream->SetCodePage(wCodePage);
132 }
133 FX_BOOL bRet = pSyntax->Init(pStream, 4096) && LoadFromSyntax(pSyntax);
134 pSyntax->Release();
135 m_wCodePage = wCodePage;
136 m_szUrl = szUrl;
137 return bRet;
138 }
LoadFromBuffer(const CFX_WideString & szUrl,const FX_WCHAR * pBuffer,int32_t iBufSize,FX_WORD wCodePage)139 FX_BOOL CFDE_CSSStyleSheet::LoadFromBuffer(const CFX_WideString& szUrl,
140 const FX_WCHAR* pBuffer,
141 int32_t iBufSize,
142 FX_WORD wCodePage) {
143 FXSYS_assert(pBuffer != NULL && iBufSize > 0);
144 IFDE_CSSSyntaxParser* pSyntax = IFDE_CSSSyntaxParser::Create();
145 if (pSyntax == NULL) {
146 return FALSE;
147 }
148 FX_BOOL bRet = pSyntax->Init(pBuffer, iBufSize) && LoadFromSyntax(pSyntax);
149 pSyntax->Release();
150 m_wCodePage = wCodePage;
151 m_szUrl = szUrl;
152 return bRet;
153 }
LoadFromSyntax(IFDE_CSSSyntaxParser * pSyntax)154 FX_BOOL CFDE_CSSStyleSheet::LoadFromSyntax(IFDE_CSSSyntaxParser* pSyntax) {
155 Reset();
156 m_pAllocator = FX_CreateAllocator(FX_ALLOCTYPE_Static, 1024, 0);
157 if (m_pAllocator == NULL) {
158 return FALSE;
159 }
160 FDE_CSSSYNTAXSTATUS eStatus;
161 do {
162 switch (eStatus = pSyntax->DoSyntaxParse()) {
163 case FDE_CSSSYNTAXSTATUS_StyleRule:
164 eStatus = LoadStyleRule(pSyntax, m_RuleArray);
165 break;
166 case FDE_CSSSYNTAXSTATUS_MediaRule:
167 eStatus = LoadMediaRule(pSyntax);
168 break;
169 case FDE_CSSSYNTAXSTATUS_FontFaceRule:
170 eStatus = LoadFontFaceRule(pSyntax, m_RuleArray);
171 break;
172 case FDE_CSSSYNTAXSTATUS_ImportRule:
173 eStatus = LoadImportRule(pSyntax);
174 break;
175 case FDE_CSSSYNTAXSTATUS_PageRule:
176 eStatus = LoadPageRule(pSyntax);
177 break;
178 default:
179 break;
180 }
181 } while (eStatus >= FDE_CSSSYNTAXSTATUS_None);
182 m_Selectors.RemoveAll();
183 m_StringCache.RemoveAll();
184 return eStatus != FDE_CSSSYNTAXSTATUS_Error;
185 }
LoadMediaRule(IFDE_CSSSyntaxParser * pSyntax)186 FDE_CSSSYNTAXSTATUS CFDE_CSSStyleSheet::LoadMediaRule(
187 IFDE_CSSSyntaxParser* pSyntax) {
188 FX_DWORD dwMediaList = 0;
189 CFDE_CSSMediaRule* pMediaRule = NULL;
190 for (;;) {
191 switch (pSyntax->DoSyntaxParse()) {
192 case FDE_CSSSYNTAXSTATUS_MediaType: {
193 int32_t iLen;
194 const FX_WCHAR* psz = pSyntax->GetCurrentString(iLen);
195 FDE_LPCCSSMEDIATYPETABLE pMediaType =
196 FDE_GetCSSMediaTypeByName(psz, iLen);
197 if (pMediaType != NULL) {
198 dwMediaList |= pMediaType->wValue;
199 }
200 } break;
201 case FDE_CSSSYNTAXSTATUS_StyleRule:
202 if (pMediaRule == NULL) {
203 SkipRuleSet(pSyntax);
204 } else {
205 FDE_CSSSYNTAXSTATUS eStatus =
206 LoadStyleRule(pSyntax, pMediaRule->GetArray());
207 if (eStatus < FDE_CSSSYNTAXSTATUS_None) {
208 return eStatus;
209 }
210 }
211 break;
212 case FDE_CSSSYNTAXSTATUS_DeclOpen:
213 if ((dwMediaList & m_dwMediaList) > 0 && pMediaRule == NULL) {
214 pMediaRule = FDE_NewWith(m_pAllocator) CFDE_CSSMediaRule(dwMediaList);
215 m_RuleArray.Add(pMediaRule);
216 }
217 break;
218 case FDE_CSSSYNTAXSTATUS_DeclClose:
219 return FDE_CSSSYNTAXSTATUS_None;
220 FDE_CSSSWITCHDEFAULTS();
221 }
222 }
223 }
LoadStyleRule(IFDE_CSSSyntaxParser * pSyntax,CFDE_CSSRuleArray & ruleArray)224 FDE_CSSSYNTAXSTATUS CFDE_CSSStyleSheet::LoadStyleRule(
225 IFDE_CSSSyntaxParser* pSyntax,
226 CFDE_CSSRuleArray& ruleArray) {
227 m_Selectors.RemoveAt(0, m_Selectors.GetSize());
228 CFDE_CSSStyleRule* pStyleRule = NULL;
229 const FX_WCHAR* pszValue = NULL;
230 int32_t iValueLen = 0;
231 FDE_CSSPROPERTYARGS propertyArgs;
232 propertyArgs.pStaticStore = m_pAllocator;
233 propertyArgs.pStringCache = &m_StringCache;
234 propertyArgs.pProperty = NULL;
235 CFX_WideString wsName;
236 for (;;) {
237 switch (pSyntax->DoSyntaxParse()) {
238 case FDE_CSSSYNTAXSTATUS_Selector: {
239 pszValue = pSyntax->GetCurrentString(iValueLen);
240 IFDE_CSSSelector* pSelector =
241 CFDE_CSSSelector::FromString(m_pAllocator, pszValue, iValueLen);
242 if (pSelector != NULL) {
243 m_Selectors.Add(pSelector);
244 }
245 } break;
246 case FDE_CSSSYNTAXSTATUS_PropertyName:
247 pszValue = pSyntax->GetCurrentString(iValueLen);
248 propertyArgs.pProperty = FDE_GetCSSPropertyByName(pszValue, iValueLen);
249 if (propertyArgs.pProperty == NULL) {
250 wsName = CFX_WideStringC(pszValue, iValueLen);
251 }
252 break;
253 case FDE_CSSSYNTAXSTATUS_PropertyValue:
254 if (propertyArgs.pProperty != NULL) {
255 pszValue = pSyntax->GetCurrentString(iValueLen);
256 if (iValueLen > 0) {
257 pStyleRule->GetDeclImp().AddProperty(&propertyArgs, pszValue,
258 iValueLen);
259 }
260 } else if (iValueLen > 0) {
261 pszValue = pSyntax->GetCurrentString(iValueLen);
262 if (iValueLen > 0) {
263 pStyleRule->GetDeclImp().AddProperty(
264 &propertyArgs, wsName, wsName.GetLength(), pszValue, iValueLen);
265 }
266 }
267 break;
268 case FDE_CSSSYNTAXSTATUS_DeclOpen:
269 if (pStyleRule == NULL && m_Selectors.GetSize() > 0) {
270 pStyleRule = FDE_NewWith(m_pAllocator) CFDE_CSSStyleRule;
271 pStyleRule->SetSelector(m_pAllocator, m_Selectors);
272 ruleArray.Add(pStyleRule);
273 } else {
274 SkipRuleSet(pSyntax);
275 return FDE_CSSSYNTAXSTATUS_None;
276 }
277 break;
278 case FDE_CSSSYNTAXSTATUS_DeclClose:
279 if (pStyleRule != NULL &&
280 pStyleRule->GetDeclImp().GetStartPosition() == NULL) {
281 pStyleRule->~CFDE_CSSStyleRule();
282 ruleArray.RemoveLast(1);
283 }
284 return FDE_CSSSYNTAXSTATUS_None;
285 FDE_CSSSWITCHDEFAULTS();
286 }
287 }
288 }
LoadFontFaceRule(IFDE_CSSSyntaxParser * pSyntax,CFDE_CSSRuleArray & ruleArray)289 FDE_CSSSYNTAXSTATUS CFDE_CSSStyleSheet::LoadFontFaceRule(
290 IFDE_CSSSyntaxParser* pSyntax,
291 CFDE_CSSRuleArray& ruleArray) {
292 CFDE_CSSFontFaceRule* pFontFaceRule = NULL;
293 const FX_WCHAR* pszValue = NULL;
294 int32_t iValueLen = 0;
295 FDE_CSSPROPERTYARGS propertyArgs;
296 propertyArgs.pStaticStore = m_pAllocator;
297 propertyArgs.pStringCache = &m_StringCache;
298 propertyArgs.pProperty = NULL;
299 for (;;) {
300 switch (pSyntax->DoSyntaxParse()) {
301 case FDE_CSSSYNTAXSTATUS_PropertyName:
302 pszValue = pSyntax->GetCurrentString(iValueLen);
303 propertyArgs.pProperty = FDE_GetCSSPropertyByName(pszValue, iValueLen);
304 break;
305 case FDE_CSSSYNTAXSTATUS_PropertyValue:
306 if (propertyArgs.pProperty != NULL) {
307 pszValue = pSyntax->GetCurrentString(iValueLen);
308 if (iValueLen > 0) {
309 pFontFaceRule->GetDeclImp().AddProperty(&propertyArgs, pszValue,
310 iValueLen);
311 }
312 }
313 break;
314 case FDE_CSSSYNTAXSTATUS_DeclOpen:
315 if (pFontFaceRule == NULL) {
316 pFontFaceRule = FDE_NewWith(m_pAllocator) CFDE_CSSFontFaceRule;
317 ruleArray.Add(pFontFaceRule);
318 }
319 break;
320 case FDE_CSSSYNTAXSTATUS_DeclClose:
321 return FDE_CSSSYNTAXSTATUS_None;
322 FDE_CSSSWITCHDEFAULTS();
323 }
324 }
325 return FDE_CSSSYNTAXSTATUS_None;
326 }
LoadImportRule(IFDE_CSSSyntaxParser * pSyntax)327 FDE_CSSSYNTAXSTATUS CFDE_CSSStyleSheet::LoadImportRule(
328 IFDE_CSSSyntaxParser* pSyntax) {
329 for (;;) {
330 switch (pSyntax->DoSyntaxParse()) {
331 case FDE_CSSSYNTAXSTATUS_ImportClose:
332 return FDE_CSSSYNTAXSTATUS_None;
333 case FDE_CSSSYNTAXSTATUS_URI:
334 break;
335 FDE_CSSSWITCHDEFAULTS();
336 }
337 }
338 }
LoadPageRule(IFDE_CSSSyntaxParser * pSyntax)339 FDE_CSSSYNTAXSTATUS CFDE_CSSStyleSheet::LoadPageRule(
340 IFDE_CSSSyntaxParser* pSyntax) {
341 return SkipRuleSet(pSyntax);
342 }
SkipRuleSet(IFDE_CSSSyntaxParser * pSyntax)343 FDE_CSSSYNTAXSTATUS CFDE_CSSStyleSheet::SkipRuleSet(
344 IFDE_CSSSyntaxParser* pSyntax) {
345 for (;;) {
346 switch (pSyntax->DoSyntaxParse()) {
347 case FDE_CSSSYNTAXSTATUS_Selector:
348 case FDE_CSSSYNTAXSTATUS_DeclOpen:
349 case FDE_CSSSYNTAXSTATUS_PropertyName:
350 case FDE_CSSSYNTAXSTATUS_PropertyValue:
351 break;
352 case FDE_CSSSYNTAXSTATUS_DeclClose:
353 return FDE_CSSSYNTAXSTATUS_None;
354 FDE_CSSSWITCHDEFAULTS();
355 }
356 }
357 return FDE_CSSSYNTAXSTATUS_None;
358 }
SetSelector(IFX_MEMAllocator * pStaticStore,const CFDE_CSSSelectorArray & list)359 void CFDE_CSSStyleRule::SetSelector(IFX_MEMAllocator* pStaticStore,
360 const CFDE_CSSSelectorArray& list) {
361 FXSYS_assert(m_ppSelector == NULL);
362 m_iSelectors = list.GetSize();
363 m_ppSelector = (IFDE_CSSSelector**)pStaticStore->Alloc(
364 m_iSelectors * sizeof(IFDE_CSSSelector*));
365 for (int32_t i = 0; i < m_iSelectors; ++i) {
366 m_ppSelector[i] = list.GetAt(i);
367 }
368 }
~CFDE_CSSMediaRule()369 CFDE_CSSMediaRule::~CFDE_CSSMediaRule() {
370 for (int32_t i = m_RuleArray.GetSize() - 1; i >= 0; --i) {
371 IFDE_CSSRule* pRule = m_RuleArray.GetAt(i);
372 switch (pRule->GetType()) {
373 case FDE_CSSRULETYPE_Style:
374 ((CFDE_CSSStyleRule*)pRule)->~CFDE_CSSStyleRule();
375 break;
376 default:
377 FXSYS_assert(FALSE);
378 break;
379 }
380 }
381 }
FDE_IsCSSChar(FX_WCHAR wch)382 inline FX_BOOL FDE_IsCSSChar(FX_WCHAR wch) {
383 return (wch >= 'a' && wch <= 'z') || (wch >= 'A' && wch <= 'Z');
384 }
FDE_GetCSSPersudoLen(const FX_WCHAR * psz,const FX_WCHAR * pEnd)385 int32_t FDE_GetCSSPersudoLen(const FX_WCHAR* psz, const FX_WCHAR* pEnd) {
386 FXSYS_assert(*psz == ':');
387 const FX_WCHAR* pStart = psz;
388 while (psz < pEnd) {
389 FX_WCHAR wch = *psz;
390 if (FDE_IsCSSChar(wch) || wch == ':') {
391 ++psz;
392 } else {
393 break;
394 }
395 }
396 return psz - pStart;
397 }
FDE_GetCSSNameLen(const FX_WCHAR * psz,const FX_WCHAR * pEnd)398 int32_t FDE_GetCSSNameLen(const FX_WCHAR* psz, const FX_WCHAR* pEnd) {
399 const FX_WCHAR* pStart = psz;
400 while (psz < pEnd) {
401 FX_WCHAR wch = *psz;
402 if (FDE_IsCSSChar(wch) || (wch >= '0' && wch <= '9') || wch == '_' ||
403 wch == '-') {
404 ++psz;
405 } else {
406 break;
407 }
408 }
409 return psz - pStart;
410 }
FromString(IFX_MEMAllocator * pStaticStore,const FX_WCHAR * psz,int32_t iLen)411 IFDE_CSSSelector* CFDE_CSSSelector::FromString(IFX_MEMAllocator* pStaticStore,
412 const FX_WCHAR* psz,
413 int32_t iLen) {
414 FXSYS_assert(pStaticStore != NULL && psz != NULL && iLen > 0);
415 const FX_WCHAR* pStart = psz;
416 const FX_WCHAR* pEnd = psz + iLen;
417 for (; psz < pEnd; ++psz) {
418 switch (*psz) {
419 case '>':
420 case '[':
421 case '+':
422 return NULL;
423 }
424 }
425 CFDE_CSSSelector *pFirst = NULL, *pLast = NULL;
426 CFDE_CSSSelector *pPersudoFirst = NULL, *pPersudoLast = NULL;
427 for (psz = pStart; psz < pEnd;) {
428 FX_WCHAR wch = *psz;
429 if (wch == '.' || wch == '#') {
430 if (psz == pStart || psz[-1] == ' ') {
431 CFDE_CSSSelector* p = FDE_NewWith(pStaticStore)
432 CFDE_CSSSelector(FDE_CSSSELECTORTYPE_Element, L"*", 1, TRUE);
433 if (p == NULL) {
434 return NULL;
435 }
436 if (pFirst != NULL) {
437 pFirst->SetType(FDE_CSSSELECTORTYPE_Descendant);
438 p->SetNext(pFirst);
439 }
440 pFirst = pLast = p;
441 }
442 FXSYS_assert(pLast != NULL);
443 int32_t iNameLen = FDE_GetCSSNameLen(++psz, pEnd);
444 if (iNameLen == 0) {
445 return NULL;
446 }
447 FDE_CSSSELECTORTYPE eType =
448 wch == '.' ? FDE_CSSSELECTORTYPE_Class : FDE_CSSSELECTORTYPE_ID;
449 CFDE_CSSSelector* p = FDE_NewWith(pStaticStore)
450 CFDE_CSSSelector(eType, psz, iNameLen, FALSE);
451 if (p == NULL) {
452 return NULL;
453 }
454 p->SetNext(pLast->GetNextSelector());
455 pLast->SetNext(p);
456 pLast = p;
457 psz += iNameLen;
458 } else if (FDE_IsCSSChar(wch) || wch == '*') {
459 int32_t iNameLen = wch == '*' ? 1 : FDE_GetCSSNameLen(psz, pEnd);
460 if (iNameLen == 0) {
461 return NULL;
462 }
463 CFDE_CSSSelector* p = FDE_NewWith(pStaticStore)
464 CFDE_CSSSelector(FDE_CSSSELECTORTYPE_Element, psz, iNameLen, TRUE);
465 if (p == NULL) {
466 return NULL;
467 }
468 if (pFirst == NULL) {
469 pFirst = pLast = p;
470 } else {
471 pFirst->SetType(FDE_CSSSELECTORTYPE_Descendant);
472 p->SetNext(pFirst);
473 pFirst = pLast = p;
474 }
475 psz += iNameLen;
476 } else if (wch == ':') {
477 int32_t iNameLen = FDE_GetCSSPersudoLen(psz, pEnd);
478 if (iNameLen == 0) {
479 return NULL;
480 }
481 CFDE_CSSSelector* p = FDE_NewWith(pStaticStore)
482 CFDE_CSSSelector(FDE_CSSSELECTORTYPE_Persudo, psz, iNameLen, TRUE);
483 if (p == NULL) {
484 return NULL;
485 }
486 if (pPersudoFirst == NULL) {
487 pPersudoFirst = pPersudoLast = p;
488 } else {
489 pPersudoLast->SetNext(p);
490 pPersudoLast = p;
491 }
492 psz += iNameLen;
493 } else if (wch == ' ') {
494 psz++;
495 } else {
496 return NULL;
497 }
498 }
499 if (pPersudoFirst == NULL) {
500 return pFirst;
501 } else {
502 pPersudoLast->SetNext(pFirst);
503 return pPersudoFirst;
504 }
505 }
506