NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

css.py (20221B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\carbonui\control\editutils\css.py
      2 import sys
      3 from carbonui.util.various_unsorted import ParseHTMLColor
      4 
      5 class css:
      6 
      7     def __init__(self):
      8         self.Reset()
      9 
     10     def Reset(self):
     11         self.classes = []
     12         self.s = {}
     13 
     14     def copy(self):
     15         new = css()
     16         new.classes = self.classes[:]
     17         return new
     18 
     19     def ApplyCSS(self, tag, attrs, attrStack):
     20         classlist = []
     21         for c in self.classes:
     22             if self.CompareSelector(attrStack[-1], c) == 1:
     23                 b = 0
     24                 if c['deptag']:
     25                     i = len(attrStack) - 2
     26                     if i < 0:
     27                         continue
     28                     for t in c['deptag']:
     29                         if b == 1 or i < 0:
     30                             break
     31                         if t['op'] == ' ':
     32                             while not self.CompareSelector(attrStack[i], t):
     33                                 i -= 1
     34                                 if i < 0:
     35                                     b = 1
     36                                     break
     37 
     38                             if i < 0:
     39                                 b = 1
     40                                 break
     41                             i -= 1
     42                         elif t['op'] == '>':
     43                             if self.CompareSelector(attrStack[i], t):
     44                                 i -= 1
     45                                 continue
     46                             else:
     47                                 b = 1
     48                                 break
     49                         elif t['op'] == '*':
     50                             i -= 1
     51                             if i < 0:
     52                                 break
     53                             while not self.CompareSelector(attrStack[i], t):
     54                                 i -= 1
     55                                 if i < 0:
     56                                     b = 1
     57                                     break
     58 
     59                             if i < 0:
     60                                 b = 1
     61                                 break
     62                             i -= 1
     63                         elif t['op'] == '+':
     64                             if attrStack[i]['lasttag'] == t['tag']:
     65                                 i -= 1
     66                                 continue
     67                             else:
     68                                 b = 1
     69                                 break
     70 
     71                 if b == 0:
     72                     classlist.append(c)
     73 
     74         classlist.sort(lambda x, y: cmp(x['prio'], y['prio']))
     75         c = {}
     76         for each in classlist:
     77             c.update(each)
     78 
     79         return c
     80 
     81     def CompareSelector(self, astack, csel):
     82         tag = astack['tag']
     83         tid = getattr(astack['attr'], 'id', None)
     84         cl = getattr(astack['attr'], 'class', '').lower()
     85         if csel['tag'] not in (tag, '*') and csel['tag']:
     86             return
     87         if csel['class']:
     88             if csel['class'] not in cl.split(' '):
     89                 return
     90         if csel['id'] and tid != csel['id']:
     91             return
     92         return 1
     93 
     94     def SplitSelector(self, sel):
     95         s = {}
     96         s['tag'] = None
     97         s['id'] = None
     98         s['class'] = None
     99         s['attr'] = None
    100         s['pclass'] = None
    101         sel = sel.strip().lower()
    102         if sel.count(':'):
    103             sel, pclass = sel.split(':', 1)
    104             s['pclass'] = pclass
    105             if sel == '':
    106                 sel = '*'
    107         ccount = sel.count('.')
    108         acount = sel.count('[')
    109         icount = sel.count('#')
    110         if ccount + acount + icount > 1:
    111             return
    112         if ccount == 1:
    113             h = sel.split('.')
    114             if len(h) == 1:
    115                 s['class'] = h[0]
    116             else:
    117                 s['tag'] = h[0]
    118                 s['class'] = h[1]
    119             return s
    120         if acount == 1:
    121             h = sel.split('[')
    122             if sel[-1] == ']':
    123                 if len(h) == 1:
    124                     s['attr'] = h[0]
    125                 else:
    126                     s['tag'] = h[0]
    127                     s['attr'] = h[1]
    128             else:
    129                 return
    130             return s
    131         if icount == 1:
    132             h = sel.split('#')
    133             if len(h) == 1:
    134                 s['id'] = h[0]
    135             else:
    136                 s['tag'] = h[0]
    137                 s['id'] = h[1]
    138             return s
    139         s['tag'] = sel
    140         return s
    141 
    142     def GetClass(self, classID):
    143         classID = classID.lower()
    144         for c in self.classes:
    145             if c['id'] == classID:
    146                 return c
    147             if c['class'] == classID:
    148                 return c
    149 
    150     def HandlePseudoClass(self, pclass):
    151         links = [('link', 'link-color'),
    152          ('visited', 'vlink-color'),
    153          ('active', 'alink-color'),
    154          ('hover', 'alink-color')]
    155         d = {}
    156         for dclass, attr in links:
    157             if pclass == dclass and 'color' in self.s:
    158                 d[attr] = self.s['color']
    159 
    160         self.s = d.copy()
    161 
    162     def ParseCSSData(self, cssdata):
    163         lines = ''
    164         for dataAndComment in cssdata.split('*/'):
    165             data = dataAndComment.split('/*', 1)[0]
    166             lines += data
    167 
    168         for styleClass in lines.split('}'):
    169             if not styleClass:
    170                 continue
    171             if styleClass.count('{') != 1:
    172                 continue
    173             attr, styles = styleClass.strip().split('{')
    174             self.s = {}
    175             prio = 0
    176             if not styles:
    177                 continue
    178             data, imp = self.ParseStyleData(styles.strip())
    179             self.ParseStyle(data)
    180             selector = depsel = depop = None
    181             prio += attr.count('.') * 100 + attr.count('#') * 1000 + attr.count('[') * 10 + attr.count(' ') + 1 - (attr.count('.') + attr.count('#') + attr.count('['))
    182             selectors = attr.replace('\t', ' ').replace('  ', ' ').strip().split(' ')
    183             selector = selectors[-1]
    184             selectors = selectors[:-1]
    185             selectors.reverse()
    186             deptags = []
    187             op = ' '
    188             for t in selectors:
    189                 if t in ('>', '*', '+'):
    190                     op = t
    191                 else:
    192                     d = self.SplitSelector(t)
    193                     if d:
    194                         d['op'] = op
    195                         deptags.append(d)
    196                         op = ' '
    197 
    198             for sel in selector.split(','):
    199                 attrs = self.SplitSelector(sel)
    200                 if attrs:
    201                     if attrs['pclass']:
    202                         self.HandlePseudoClass(attrs['pclass'])
    203                     s = self.s.copy()
    204                     s['tag'] = attrs['tag']
    205                     s['class'] = attrs['class']
    206                     s['id'] = attrs['id']
    207                     s['attr'] = attrs['attr']
    208                     s['deptag'] = deptags
    209                     s['prio'] = prio
    210                     self.classes.append(s)
    211 
    212             if len(imp):
    213                 self.s = {}
    214                 self.ParseStyle(imp)
    215                 for sel in selector.split(','):
    216                     attrs = self.SplitSelector(sel)
    217                     if attrs:
    218                         if attrs['pclass']:
    219                             self.HandlePseudoClass(attrs['pclass'])
    220                         s = self.s.copy()
    221                         s['tag'] = attrs['tag']
    222                         s['class'] = attrs['class']
    223                         s['id'] = attrs['id']
    224                         s['attr'] = attrs['attr']
    225                         s['deptag'] = deptags
    226                         s['prio'] = 10000
    227                     self.classes.append(s)
    228 
    229     def ParseStyleData(self, cssdata):
    230         data = {}
    231         imp = {}
    232         for attrAndValue in cssdata.split(';'):
    233             if not attrAndValue:
    234                 continue
    235             if ':' in attrAndValue:
    236                 attr, value = attrAndValue.strip().split(':', 1)
    237             else:
    238                 continue
    239             if attr and value:
    240                 attr = attr.strip().lower()
    241                 if '!' in value:
    242                     value, important = value.split('!', -1)
    243                     if important.strip().lower() == 'important':
    244                         imp[attr] = value.strip()
    245                         continue
    246                 data[attr] = value.strip()
    247 
    248         return (data, imp)
    249 
    250     def ParseCSS(self, attrs = None):
    251         self.s = {}
    252         sattr = getattr(attrs, 'style', None)
    253         if sattr:
    254             data, imp = self.ParseStyleData(sattr)
    255             data.update(imp)
    256             return self.ParseStyle(data)
    257 
    258     def ParseStyle(self, style = None):
    259         if style:
    260             for k, v in style.iteritems():
    261                 if k in self.styleDict:
    262                     eval('self.%s' % self.styleDict[k])(k, v)
    263 
    264         return self.s
    265 
    266     def ParseStyleNum(self, value):
    267         value = unicode(value).lower().strip()
    268         if value.isdigit():
    269             return int(value)
    270         if value.endswith('%'):
    271             return value
    272         if value[-2:] in self.absStyleUnits and value[:-2].isdigit():
    273             return int(self.absStyleUnits[value[-2:]] * float(value[:-2].strip()))
    274         try:
    275             return int(value)
    276         except:
    277             sys.exc_clear()
    278             return None
    279 
    280     absStyleUnits = {'px': 1.0,
    281      'in': 100.0,
    282      'cm': 100.0 / 2.54,
    283      'mm': 100.0 / 25.4,
    284      'pt': 100.0 / 72.0,
    285      'pc': 100.0 / 6.0}
    286 
    287     def ParseFontSize(self, k, v):
    288         if v:
    289             if not v.isdigit():
    290                 if v in self.fontSize:
    291                     v = self.fontSize[v]
    292             v = self.ParseStyleNum(v)
    293             if v is None or not type(v) == int and not v.isdigit():
    294                 return
    295             self.s['font-size'] = int(v)
    296 
    297     def ParseFontStyle(self, k, v):
    298         if v:
    299             if v == 'normal':
    300                 self.s['font-style'] = 'n'
    301             if v in ('italic', 'oblique'):
    302                 self.s['font-style'] = 'i'
    303 
    304     def ParseFontWeight(self, k, v):
    305         if v:
    306             if v == 'normal':
    307                 self.s['font-weight'] = 'n'
    308             elif v in ('bold', 'bolder'):
    309                 self.s['font-weight'] = 'b'
    310 
    311     def ParseTextDecoration(self, k, v):
    312         if v:
    313             if v == 'none':
    314                 self.s['text-decoration'] = ''
    315                 return
    316             s = unicode(v)
    317             s = s.replace('underline', 'u').replace('line-through', 's').replace('overline', 'o')
    318             for t in s:
    319                 if t.strip() not in ('u', 's', 'o'):
    320                     return
    321 
    322             self.s['text-decoration'] = s
    323 
    324     def ParseTextAlign(self, k, v):
    325         if v in ('left', 'right', 'center'):
    326             self.s['text-align'] = v
    327 
    328     def ParseFont(self, k, v):
    329         if v:
    330             for param in v.split(' '):
    331                 self.ParseFontSize('', param)
    332                 self.ParseFontStyle('', param)
    333                 self.ParseFontWeight('', param)
    334                 self.ParseTextDecoration('', param)
    335 
    336     def ParseMargin(self, k, v):
    337         if v:
    338             a = []
    339             for p in v.replace('  ', ' ').split(' '):
    340                 p = self.ParseStyleNum(p)
    341                 if p:
    342                     a.append(p)
    343 
    344             if len(a) > 0:
    345                 self.s['margin-left'] = a[[0,
    346                  1,
    347                  1,
    348                  3][len(a) - 1]]
    349                 self.s['margin-right'] = a[[0,
    350                  1,
    351                  1,
    352                  1][len(a) - 1]]
    353                 self.s['margin-top'] = a[[0,
    354                  0,
    355                  0,
    356                  0][len(a) - 1]]
    357                 self.s['margin-bottom'] = a[[0,
    358                  0,
    359                  2,
    360                  2][len(a) - 1]]
    361 
    362     def ParsePadding(self, k, v):
    363         if v:
    364             v = self.ParseStyleNum(v)
    365             if v:
    366                 self.s['padding-left'] = self.s['padding-right'] = v
    367                 self.s['padding-top'] = self.s['padding-bottom'] = v
    368 
    369     def ParseBorderWidth(self, k, v):
    370         if v:
    371             if v in self.borderWidths:
    372                 v = self.borderWidths[v]
    373             else:
    374                 v = self.ParseStyleNum(v)
    375             if v:
    376                 if k == 'border-width':
    377                     for i in ('left', 'right', 'top', 'bottom'):
    378                         self.s['border-' + i + '-width'] = v
    379 
    380                 else:
    381                     self.s[k] = v
    382 
    383     def ParseBorderColor(self, k, v):
    384         if v:
    385             v = ParseHTMLColor(v, 1, error=1)
    386             if v:
    387                 self.s['border-left-color'] = self.s['border-right-color'] = v
    388                 self.s['border-top-color'] = self.s['border-bottom-color'] = v
    389 
    390     def ParseBorderStyles(self, k, v):
    391         if v:
    392             if v in self.borderStyles:
    393                 self.s[k] = self.borderStyles[v]
    394 
    395     def ParseBorderStyle(self, k, v):
    396         if v in self.borderStyles:
    397             self.s['border-left-style'] = self.borderStyles[v]
    398             self.s['border-right-style'] = self.borderStyles[v]
    399             self.s['border-top-style'] = self.borderStyles[v]
    400             self.s['border-bottom-style'] = self.borderStyles[v]
    401 
    402     def ParseBorder(self, k, v):
    403         for each in v.split(' '):
    404             if each in self.borderStyles:
    405                 self.ParseBorderStyle(k, each)
    406                 continue
    407             self.ParseBorderColor(k, each)
    408             self.ParseBorderWidth('border-width', each)
    409 
    410     def ParseBorders(self, k, v):
    411         for each in v.split(' '):
    412             if each in self.borderStyles:
    413                 self.ParseBorderStyles(k, each)
    414                 continue
    415             self.ParseColor(k + '-color', each)
    416             self.ParseBorder(k + '-width', each)
    417 
    418     def ParseBorderCollapse(self, k, v):
    419         if v in self.borderCollapse:
    420             self.s['border-collapse'] = self.borderCollapse[v]
    421         else:
    422             self.s['border-collapse'] = 0
    423 
    424     def ParseColor(self, k, v):
    425         if v:
    426             v = ParseHTMLColor(v, 1, error=1)
    427             if v:
    428                 self.s[k] = v
    429 
    430     def ParseBackground(self, k, v):
    431         for each in v.split(' '):
    432             each = each.replace(' ', '').lower()
    433             if each.find('url(') != -1:
    434                 self.ParseBackgroundImage(None, each)
    435             elif each.find('repeat') != -1:
    436                 self.ParseBackgroundRepeat(None, each)
    437             elif v:
    438                 color = ParseHTMLColor(each, 1, error=1)
    439                 if color:
    440                     self.s['background-color'] = color
    441 
    442     def ParseBackgroundRepeat(self, k, v):
    443         if v in ('repeat', 'repeat-x', 'repeat-y', 'no-repeat'):
    444             self.s['background-repeat'] = v
    445 
    446     def ParseBackgroundImage(self, k, v):
    447         if v and v.startswith('url(') and v.endswith(')'):
    448             self.s['background-image'] = v[4:-1]
    449 
    450     def ParseBackgroundAttachment(self, k, v):
    451         if v in ('fixed', 'scroll'):
    452             self.s['background-attachment'] = v
    453 
    454     def ParseBackgroundPosition(self, k, v):
    455         if v:
    456             v = v.split(' ')
    457             if len(v) in (2, 4):
    458                 self.ParseAbsSize('background-image-left', v[0])
    459                 self.ParseAbsSize('background-image-top', v[1])
    460             if len(v) == 4:
    461                 self.ParseAbsSize('background-image-width', v[2])
    462                 self.ParseAbsSize('background-image-height', v[3])
    463             self.s['background-position'] = []
    464             for i in v:
    465                 if i in ('top', 'center', 'middle', 'bottom', 'left', 'right'):
    466                     self.s['background-position'].append(i)
    467 
    468     def ParseAbsSize(self, k, v):
    469         if v:
    470             v = self.ParseStyleNum(v)
    471             if v:
    472                 self.s[k] = int(v)
    473 
    474     def ParsePosAbsSize(self, k, v):
    475         if v:
    476             v = self.ParseStyleNum(v)
    477             if v:
    478                 if type(v) == int:
    479                     self.s[k] = max(v, 0)
    480                 else:
    481                     self.s[k] = v
    482 
    483     def ParseVerticalAlign(self, k, v):
    484         if v in self.vertStyles:
    485             self.s['vertical-align'] = self.vertStyles[v]
    486 
    487     def ParseHorizontalAlign(self, k, v):
    488         if v in ('left', 'right', 'center'):
    489             self.s['horizontal-align'] = v
    490 
    491     def ParsePosition(self, k, v):
    492         if v in ('absolute', 'fixed', 'relative', 'static'):
    493             self.s['position'] = v
    494 
    495     def ParseFloat(self, k, v):
    496         if v in ('left', 'right'):
    497             self.s['float'] = v
    498         elif v == 'none':
    499             self.s['float'] = None
    500         elif v == 'inherit' and 'float' in self.s:
    501             del self.s['float']
    502 
    503     fontSize = {'small': 8,
    504      'x-small': 7,
    505      'xx-small': 6,
    506      'smaller': 8,
    507      'medium': 10,
    508      'large': 12,
    509      'larger': 14,
    510      'x-large': 20}
    511     vertStyles = {'top': 0,
    512      'middle': 1,
    513      'bottom': 2,
    514      'baseline': 3,
    515      'sub': 4,
    516      'super': 5}
    517     borderStyles = {'none': None,
    518      'hidden': 0,
    519      'solid': 1,
    520      'groove': 2,
    521      'ridge': 2,
    522      'inset': 2,
    523      'outset': 2}
    524     borderWidths = {'thin': 1,
    525      'medium': 2,
    526      'thick': 3}
    527     borderCollapse = {'seperate': 0,
    528      'collapse': 1}
    529     absStyles = ('text-indent', 'margin-left', 'margin-right', 'margin-top', 'margin-bottom', 'padding-left', 'padding-right', 'padding-top', 'padding-bottom', 'border-left-width', 'border-right-width', 'border-top-width', 'border-bottom-width', 'letter-spacing', 'word-spacing', 'line-height')
    530     styleDict = {'text-indent': 'ParseAbsSize',
    531      'margin-left': 'ParsePosAbsSize',
    532      'margin-right': 'ParsePosAbsSize',
    533      'margin-top': 'ParsePosAbsSize',
    534      'margin-bottom': 'ParsePosAbsSize',
    535      'padding-left': 'ParsePosAbsSize',
    536      'padding-right': 'ParsePosAbsSize',
    537      'padding-top': 'ParsePosAbsSize',
    538      'padding-bottom': 'ParsePosAbsSize',
    539      'border-left-width': 'ParseBorderWidth',
    540      'border-right-width': 'ParseBorderWidth',
    541      'border-top-width': 'ParseBorderWidth',
    542      'border-bottom-width': 'ParseBorderWidth',
    543      'border-left-style': 'ParseBorderStyles',
    544      'border-right-style': 'ParseBorderStyles',
    545      'border-top-style': 'ParseBorderStyles',
    546      'border-bottom-style': 'ParseBorderStyles',
    547      'letter-spacing': 'ParseAbsSize',
    548      'word-spacing': 'ParseAbsSize',
    549      'line-height': 'ParsePosAbsSize',
    550      'font-size': 'ParseFontSize',
    551      'font-weight': 'ParseFontWeight',
    552      'font-style': 'ParseFontStyle',
    553      'text-decoration': 'ParseTextDecoration',
    554      'text-align': 'ParseTextAlign',
    555      'font': 'ParseFont',
    556      'margin': 'ParseMargin',
    557      'padding': 'ParsePadding',
    558      'border-width': 'ParseBorderWidth',
    559      'border-color': 'ParseBorderColor',
    560      'border-style': 'ParseBorderStyle',
    561      'border': 'ParseBorder',
    562      'border-left': 'ParseBorders',
    563      'border-right': 'ParseBorders',
    564      'border-top': 'ParseBorders',
    565      'border-bottom': 'ParseBorders',
    566      'color': 'ParseColor',
    567      'link-color': 'ParseColor',
    568      'alink-color': 'ParseColor',
    569      'vlink-color': 'ParseColor',
    570      'background': 'ParseBackground',
    571      'background-color': 'ParseColor',
    572      'border-left-color': 'ParseColor',
    573      'border-right-color': 'ParseColor',
    574      'border-top-color': 'ParseColor',
    575      'border-bottom-color': 'ParseColor',
    576      'vertical-align': 'ParseVerticalAlign',
    577      'align': 'ParseHorizontalAlign',
    578      'background-repeat': 'ParseBackgroundRepeat',
    579      'background-image': 'ParseBackgroundImage',
    580      'background-image-color': 'ParseColor',
    581      'background-image-width': 'ParseAbsSize',
    582      'background-image-height': 'ParseAbsSize',
    583      'background-image-left': 'ParseAbsSize',
    584      'background-image-top': 'ParseAbsSize',
    585      'background-attachment': 'ParseBackgroundAttachment',
    586      'background-position': 'ParseBackgroundPosition',
    587      'border-collapse': 'ParseBorderCollapse',
    588      'position': 'ParsePosition',
    589      'float': 'ParseFloat',
    590      'left': 'ParseAbsSize',
    591      'right': 'ParseAbsSize',
    592      'top': 'ParseAbsSize',
    593      'bottom': 'ParseAbsSize',
    594      'width': 'ParsePosAbsSize',
    595      'min-width': 'ParsePosAbsSize',
    596      'max-width': 'ParsePosAbsSize',
    597      'height': 'ParsePosAbsSize',
    598      'min-height': 'ParsePosAbsSize',
    599      'max-height': 'ParsePosAbsSize'}