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