#!/usr/bin/env python "Accessibility CSS Generator, (c) Silas S. Brown 2006-24. Version 0.9937" # Works on either Python 2 or Python 3 # Website: http://ssb22.user.srcf.net/css/ # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # CHANGES # ------- # If you want to compare this code to old versions, the old # versions are being kept in the E-GuideDog SVN repository on # http://svn.code.sf.net/p/e-guidedog/code/ssb22/css-generator # and on GitHub at https://github.com/ssb22/css-generator # and on GitLab at https://gitlab.com/ssb22/css-generator # and on BitBucket https://bitbucket.org/ssb22/css-generator # and at https://gitlab.developers.cam.ac.uk/ssb22/css-generator # and in China: https://gitee.com/ssb22/css-generator # as of v0.9782. Versions prior to that were not kept, but # some were captured by Internet Archive at # https://web.archive.org/web/*/http://people.pwf.cam.ac.uk/ssb22/css/css-generate.py # CONFIGURATION # ------------- # The default configuration can be changed here, or if you # prefer you can copy and paste all of this to a separate # file called css_generate_config.py and edit it there # (which should make it easier to update the code # independently of your configuration). # Where to put the output CSS files: default is current directory, # but you might want to put them in a subdirectory, or set # an absolute path outputDir = "." try: True # backward compatibility with Python 2.1: except: exec("True,False=1,0") # (syntax error in Python 3) # Whether to write an HTML menu to standard output as well # (see my CSS page for example) outHTML = True # if putting this on the Web, include in .htaccess: # AddType text/css css # SetEnvIf Request_URI "\.css$" requested_css=css # Header add Content-Disposition "Attachment" env=requested_css # Which pixel sizes to generate. # Size 0 means "unchanged" - it will disable the size # changes, and the layout changes that are meant for large # sizes. This is for people who need only colour changes, # or for whom the browser's built-in zoom is sufficient # (e.g. on a large display and/or complex layouts that # aren't very-well dealt with by our layout changes). pixel_sizes_to_generate = [0,18,20,25,30,35,40,45,50,60,75,100] # Which pixel size to use with the "chop" and related debug options: chop_pixel_size = 20 # Which colour schemes to generate. The format of this is # [("description","filename-prefix",{...}),...] # - see the existing ones for examples. # If you have many of these, you might want to read them # in from separate configuration files instead of listing # them here. In that case, set colour_schemes_to_generate # to a string containing a wildcard, # e.g. colour_schemes_to_generate = "my_config_dir/*.conf" # in which case each file in my_config_dir/*.conf should # contain one or more entries in the same [(...),...] format # WARNING: this will be passed to Python's eval() function # which can execute any command, so don't allow an # untrusted third party to write these *.conf files. colour_schemes_to_generate = [ ("yellow on black","", {"text":"yellow","background":"black", "translucent_background_compromise":"rgba(0,0,0,0.5)", "headings":"#8080FF","link":"#00FF00", "hover-bkg":"#0000C0","visited":"#00FFFF", "bold":"#FFFF80","italic":"white", "coloured":"pink", # used for text inside any FONT COLOR= markup "button-bkg":"#600040", "select-bkg":"#600060", "reset-bkg":"#400060", "form_disabled":"#404040", # GrayText requires CSS 2.1 "selection-bkg":"#006080", # (if supported by the browser. BEWARE: Some browsers, e.g. Safari 6, will NOT display this exact colour, but a computed medium mid-way between it and the unselected background; you should therefore ensure that other backgrounds (e.g. highlight) are discernable against those 'computed medium' colours as well) "highlight-bkg":"#300030", # (misc non-selection highlights in site-specific hacks) "image_transparency_compromise":"#808000" # non-black and non-white background for transparent images, so at least stand a chance of seeing transparent imgs that were meant for white bkg (or black bkg) }), ("green on black","green", {"text":"#00FF00","background":"black", "translucent_background_compromise":"rgba(0,0,0,0.5)", "headings":"#40C080","link":"#008AFF", "hover-bkg":"#400000","visited":"#00FFFF", "bold":"#80FF80","italic":"white", "button-bkg":"#600040", "select-bkg":"#600060", "coloured":"#80C040", "reset-bkg":"#400060", "form_disabled":"#404040", "selection-bkg":"#4000c0", "highlight-bkg":"#003050", "image_transparency_compromise":"#808000" }), ("white on black","WonB", {"text":"white","background":"black", "translucent_background_compromise":"rgba(0,0,0,0.5)", "headings":"#40C090","link":"#0080FF", "hover-bkg":"#400000","visited":"#00FFFF", "bold":"yellow","italic":"#FFFF80", "button-bkg":"#600040", "select-bkg":"#600060", "coloured":"#FFFF40", "reset-bkg":"#400060", "form_disabled":"#404040", "selection-bkg":"#4080c0", "highlight-bkg":"#003050", "image_transparency_compromise":"#808080" }), ("soft greys","soft", # c.f. Nightshift etc; thanks to Liviu Andronic for testing {"text":"#C0C0C0","background":"#383838", "translucent_background_compromise":"rgba(56,56,56,0.5)", "alt-backgrounds":["#333333","#2E2E2E"], # optional "headings":"#40C090","link":"#BDB76B", "hover-bkg":"#453436","visited":"#B6AA7B", "bold":"#CD853F","italic":"#EFEFCF", "button-bkg":"#553030", "select-bkg":"#603440", "coloured":"#E0E040", "reset-bkg":"#303055", "form_disabled":"#555753", "selection-bkg":"#5f5f5f", "highlight-bkg":"#2e3050", "focusOutlineStyle":"solid #006080", "image_opacity":0.8, "image_transparency_compromise":"#2e3436" }), ("black on linen","BonL", # LyX's background colour is "linen", 240/230/220 {"text":"black","background":"#faf0e6", "translucent_background_compromise":"rgba(250,240,230,0.5)", "headings":"#404040","link":"#0000FF", "hover-bkg":"#80C0C0","visited":"#008020", "bold":"black","italic":"#400000", "button-bkg":"#608040", "select-bkg":"#608060", "coloured":"#001040", "reset-bkg":"#408060", "form_disabled":"#A0A0A0", "highlight-bkg":"#FFFFE6", "image_transparency_compromise":"#faf0e6" }), ("black on white","BonW", # cld call this "black on bright white" (as opposed to "black on linen white") but that causes the list to take up more width {"text":"black","background":"white", "translucent_background_compromise":"rgba(255,255,255,0.5)", "headings":"#404040","link":"#0000FF", "hover-bkg":"#80C0C0","visited":"#008020", "bold":"black","italic":"#400000", "button-bkg":"#608040", "select-bkg":"#608060", "coloured":"#001040", "reset-bkg":"#408060", "form_disabled":"#A0A0A0", "highlight-bkg":"#FFFF80", "image_transparency_compromise":"white" }), ] # Some other options you might want to change: separate_adjacent_links_at_size_0 = False # sometimes interferes with layouts separate_adjacent_links_at_other_sizes = True # Fonts: (cjk_fonts is listed first so it can be used in both serif_fonts and sans_serif_fonts) cjk_fonts = "Lantinghei SC, AppleGothic" # AppleGothic must be listed or Korean is broken on Mac OS 10.7 # Lantinghei SC was introduced to OS X in 10.9, which is handy because the previously-good STSong font (which was the system default for Simplified Chinese) broke on 10.9: it renders badly with antialiasing turned off at 20px, e.g. missing the horizontal stroke on U+95E8. So we set Lantinghei SC for 10.9 but fall back to STSong on 10.8/10.7/etc (I don't think we need to explicitly say STSong, and there are advantages in not doing so, e.g. the TODO below about :lang(ja) is not relevant for pre-10.9 systems) # TODO: for :lang(ko) and :lang(ja) we had better put AppleGothic and a Japanese font like YuGothic first (before Lantinghei) - see below re U+8D77, U+95E8 etc. Pity can't read the system preferences for pages that don't set a CJK value of LANG. This :lang exception needs to be done separately for every element that has a font-family, to avoid corrupting headings etc. # Other Mac CJK fonts to be aware of: MingLiU prefers full 'Traditional' forms of characters where Trad/Simp has same Unicode value (e.g. U+8D77 'qi3' has an extra vertical stroke making the 'ji' component look more like a 'si'); renders OK on Mac OS 10.9 at 20px without antialias, but might not always be present (the ttf is installed to /Library/Fonts/Microsoft by MS Office and is not present on machines without MS Office). Arial Unicode MS (present on both 10.7 and 10.9) has some issues with baselines not lining up e.g. in the word 'zhen1li3' U+771F U+7406; it prefers Simplifed Chinese forms (e.g. U+8D77 uses 'ji', and U+95E8 is the Chinese rather than the Japanese simplification). GB18030 Bitmap (NISC18030) might work at 16px, 32px etc, but scales badly to other sizes. "Hei" has irregular stroke widths in 10.9 20px no-antialias, but otherwise OK serif_fonts = "Times New Roman, times, utopia, /* charter, */ "+cjk_fonts+", serif" # TNR is listed first for the benefit of broken Xft systems that need the MS fonts to make them look OK. Shouldn't have any effect on other systems. sans_serif_fonts = "helvetica, arial, verdana, "+cjk_fonts+", sans-serif" # (TODO: do we want different cjk_fonts here?) pinyin_fonts = "FreeSerif, Lucida Sans Unicode, Times New Roman, DejaVu Sans, serif" # try to get clear tone marks (but DejaVu Sans must be low priority because it results in disappearing text on some buggy Safari versions under Mac OS 10.7) browser_is_Firefox_73 = False # set this to True ONLY if you are using Firefox 73, to work around bug 1616243. Do NOT set it to True on Firefox 74+ as it will make checkboxes unreadable. # ---- End of options (but read on for debugging) ---- # DEBUGGING BY BINARY CHOP: If a complex stylesheet exhibits # a behaviour you weren't expecting (maybe due to a browser # bug but maybe not) then it might not be obvious how to fix # it. This program has a debug mode that helps you do it by # binary chop. Run like this: # python css-generate.py chop # which will generate a single debug .css file with half # the attributes disabled. Try that debug .css; if the # problem persisted, then do # python css-generate.py chop 1 # or if the problem did not persist, do # python css-generate.py chop 0 # and then try again. Then add another 1 or 0 depending on # whether or not the problem persisted the next time, e.g. # python css-generate.py chop 01 # Hopefully it will narrow down the problem to one thing. # You will see which one that is from the debug messages # it prints on standard output (these will appear instead of # the HTML index of stylesheets that is usually generated). chop_extra_verification = True # If True, we'll take an extra step to verify each chop result (by checking we get the opposite in the inverse set) before further subdivisions # For more desperate debugging cases, you can try: # python css-generate.py desperate-debug # which will generate a large number of stylesheets, each # adding one more rule and not combining. (Note that some # rules at the beginning and end of the stylesheet will be # there unconditionally though.) # TODO consider forcing "display" to its normal value (not "none") # if some sites are going to use stock scripts that switch them on and # off every few seconds inadvertently making the rest of the page dance around # ---- End of debugging info, code follows ---- try: from css_generate_config import * except ImportError: pass try: any except: # backward compatibility with Python 2.1: def any(l): for i in l: if i: return True try: dict except: def dict(l): r = {} for k,v in l: r[k] = v return r try: set except: def set(l): return l try: sorted except: def sorted(l,cmpFunc=None): r = l[:] r.sort(cmpFunc) return r try: reduce # Python 2 except: # Python 3 from functools import reduce, cmp_to_key _builtin_sorted = sorted def sorted(l,theCmp=None): if theCmp: return _builtin_sorted(l,key=cmp_to_key(theCmp)) else: return _builtin_sorted(l) def cmp(a,b): return (a>b)-(a tspan'] # used within svg, sometimes for nothing more than effect (unfortunately there doesn't seem to be a way of ensuring the containing svg is displayed large enough, but truncation is better than having the text go underneath other elements) mostElements += html5Elements mostElements += ['location'] # site-specific hack for lib.cam.ac.uk css={} ; printOverride = {} webkitScreenOverride = {} ; geckoScreenOverride = {} ; msieScreenOverride = {} webkitGeckoScreenOverride = {} ; webkitMsieScreenOverride = {} ; geckoMsieScreenOverride = {} for e in mostElements+rubyElements: css[e]=defaultStyle.copy() printOverride[e] = {"color":"black","background":"white"}.copy() printOverride[e]["*font-size"] = "12pt" # TODO: option? geckoMsieScreenOverride[e] = {"*column-count":"1"} # not Webkit (PageUp/PageDown bug in Chrome57 etc) # but there are some exceptions: for e in rubyElements: del css[e]["*text-align"] if not pixelSize: # We want div's background to have some transparency, because some sites position