| 1 | import os |
|---|
| 2 | import time |
|---|
| 3 | from fontTools.pens.basePen import BasePen |
|---|
| 4 | from template import tail, testCaseShowRecordsHead, testCaseShowGlyphsHead |
|---|
| 5 | from glyphRecordsToHTML import glyphRecordsToHTML |
|---|
| 6 | try: |
|---|
| 7 | from cElementTree import fromstring |
|---|
| 8 | except ImportError: |
|---|
| 9 | from elementtree.ElementTree import fromstring |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | def makeHTML(resultsXML, font, showGlyphs=True, showNotes=True, showPassed=True, glyphPointSize=20): |
|---|
| 13 | html = [] |
|---|
| 14 | |
|---|
| 15 | canvasCounter = 1 |
|---|
| 16 | engineChangeCounter = 1 |
|---|
| 17 | testCaseCounter = 1 |
|---|
| 18 | pathCache = {} |
|---|
| 19 | canvasData = [] |
|---|
| 20 | |
|---|
| 21 | tree = fromstring(resultsXML) |
|---|
| 22 | for element in tree: |
|---|
| 23 | if element.tag == "statistics": |
|---|
| 24 | html += _logStatistics(element) |
|---|
| 25 | elif element.tag == "engineChanges": |
|---|
| 26 | html += _logEngineChanges(element, engineChangeCounter) |
|---|
| 27 | engineChangeCounter += 1 |
|---|
| 28 | elif element.tag == "note": |
|---|
| 29 | if not showNotes: |
|---|
| 30 | continue |
|---|
| 31 | html.append("<p class=\"testCaseNote\">%s</p>" % element.get("text")) |
|---|
| 32 | elif element.tag == "test": |
|---|
| 33 | html.append("<h2 class=\"withDisclosure\" id=\"testCase%d_head\" onclick=\"toggle('testCase%d');\">Test Case %d</h2>" % (testCaseCounter, testCaseCounter, testCaseCounter)) |
|---|
| 34 | html.append("<div id=\"testCase%d\">" % testCaseCounter) |
|---|
| 35 | testCaseCounter += 1 |
|---|
| 36 | input = result = expectedResult = None |
|---|
| 37 | for subElement in element: |
|---|
| 38 | if subElement.tag == "input": |
|---|
| 39 | input = subElement |
|---|
| 40 | elif subElement.tag == "result": |
|---|
| 41 | result = subElement |
|---|
| 42 | elif subElement.tag == "expectedResult": |
|---|
| 43 | expectedResult = subElement |
|---|
| 44 | if showGlyphs: |
|---|
| 45 | for subElement in [input, result, expectedResult]: |
|---|
| 46 | if subElement is None: |
|---|
| 47 | continue |
|---|
| 48 | for record in subElement: |
|---|
| 49 | name = record.get("name") |
|---|
| 50 | if name not in pathCache: |
|---|
| 51 | pathCache[name] = _getCanvasGlyphData(name, font) |
|---|
| 52 | # input |
|---|
| 53 | if subElement.tag == "input": |
|---|
| 54 | html.append("<div class=\"testCaseInputCanvasContainer\"><canvas id=\"canvas%d\"></canvas></div>" % canvasCounter) |
|---|
| 55 | canvasData.append("[\"canvas%d\", [%s]]," % (canvasCounter, _glyphRecordsToCanvas(subElement))) |
|---|
| 56 | canvasCounter += 1 |
|---|
| 57 | # result |
|---|
| 58 | elif subElement.tag == "result": |
|---|
| 59 | html.append("<div class=\"testCaseResultCanvasContainer\"><canvas id=\"canvas%d\"></canvas></div>" % canvasCounter) |
|---|
| 60 | canvasData.append("[\"canvas%d\", [%s]]," % (canvasCounter, _glyphRecordsToCanvas(subElement))) |
|---|
| 61 | canvasCounter += 1 |
|---|
| 62 | # expected result |
|---|
| 63 | elif subElement is not None: |
|---|
| 64 | if subElement.get("passed") == "True": |
|---|
| 65 | if not showPassed: |
|---|
| 66 | continue |
|---|
| 67 | c = "testCaseExpectedResultPassedCanvasContainer" |
|---|
| 68 | else: |
|---|
| 69 | c = "testCaseExpectedResultFailedCanvasContainer" |
|---|
| 70 | html.append("<div class=\"%s\"><canvas id=\"canvas%d\"></canvas></div>" % (c, canvasCounter)) |
|---|
| 71 | canvasData.append("[\"canvas%d\", [%s]]," % (canvasCounter, _glyphRecordsToCanvas(subElement))) |
|---|
| 72 | canvasCounter += 1 |
|---|
| 73 | else: |
|---|
| 74 | showPositions = True |
|---|
| 75 | if expectedResult: |
|---|
| 76 | showPositions = False |
|---|
| 77 | for i in expectedResult: |
|---|
| 78 | if i.get("xAdvance") != "None" or i.get("yAdvance") != "None"\ |
|---|
| 79 | or i.get("xPlacement") != "None" or i.get("yPlacement") != "None": |
|---|
| 80 | showPositions = True |
|---|
| 81 | break |
|---|
| 82 | html += _logInputAsString(input) |
|---|
| 83 | html += _logResultAsString(subElement, showPositions) |
|---|
| 84 | if expectedResult: |
|---|
| 85 | html += _logExpectedResultAsString(subElement, showPositions) |
|---|
| 86 | html.append("</div>") |
|---|
| 87 | if showGlyphs: |
|---|
| 88 | head = testCaseShowGlyphsHead |
|---|
| 89 | head = head.replace("<!-- FONT UPM -->", str(font.info.unitsPerEm)) |
|---|
| 90 | head = head.replace("<!-- FONT DESCENDER -->", str(font.info.descender)) |
|---|
| 91 | head = head.replace("<!-- GLYPH POINT SIZE -->", str(float(glyphPointSize))) |
|---|
| 92 | glyphData = [] |
|---|
| 93 | for k, v in pathCache.items(): |
|---|
| 94 | glyphData.append("\"%s\" : %s," % (k, v)) |
|---|
| 95 | glyphData = "\n".join(glyphData) |
|---|
| 96 | head = head.replace("<!-- GLYPH DEFINITIONS -->", glyphData) |
|---|
| 97 | canvasData = "\n".join(canvasData) |
|---|
| 98 | head = head.replace("<!-- ALL CANVAS DATA -->", canvasData) |
|---|
| 99 | else: |
|---|
| 100 | head = testCaseShowRecordsHead |
|---|
| 101 | html.insert(0, head) |
|---|
| 102 | html.append(tail) |
|---|
| 103 | text = "\n".join(html) |
|---|
| 104 | return text |
|---|
| 105 | |
|---|
| 106 | def _logStatistics(element): |
|---|
| 107 | html = [] |
|---|
| 108 | data = {} |
|---|
| 109 | for subElement in element: |
|---|
| 110 | data[subElement.tag] = subElement.get("value") |
|---|
| 111 | for i in ["runTime", "passedTests", "failedTests"]: |
|---|
| 112 | if i == "runTime": |
|---|
| 113 | value = "Ran %s tests in %s" % (data["totalTests"], data["runTime"]) |
|---|
| 114 | elif i == "passedTests": |
|---|
| 115 | value = "%s passed" % data[i] |
|---|
| 116 | else: |
|---|
| 117 | value = "%s failed" % data[i] |
|---|
| 118 | s = "<h1>%s</h1>" % value |
|---|
| 119 | html.append(s) |
|---|
| 120 | return html |
|---|
| 121 | |
|---|
| 122 | def _logEngineChanges(element, index): |
|---|
| 123 | html = ["<h2 class=\"withDisclosure\" id=\"settings%d_head\" onclick=\"toggle('settings%d');\">Settings</h2><div id=\"settings%d\">" % (index, index, index)] |
|---|
| 124 | for subElement in element: |
|---|
| 125 | if subElement.tag == "featureStates": |
|---|
| 126 | for stateGroup in subElement: |
|---|
| 127 | if stateGroup.tag == "featuresOn": |
|---|
| 128 | title = "On" |
|---|
| 129 | else: |
|---|
| 130 | title = "Off" |
|---|
| 131 | s = "<h3>Features %s:</h3>" % title |
|---|
| 132 | html.append(s) |
|---|
| 133 | for i in stateGroup: |
|---|
| 134 | s = "<p class=\"testCaseFeature\">%s</p>" % i.get("name") |
|---|
| 135 | html.append(s) |
|---|
| 136 | continue |
|---|
| 137 | elif subElement.tag == "script": |
|---|
| 138 | title = "Script" |
|---|
| 139 | value = subElement.get("value") |
|---|
| 140 | elif subElement.tag == "language": |
|---|
| 141 | title = "Language" |
|---|
| 142 | value = subElement.get("value") |
|---|
| 143 | elif subElement.tag == "textDirection": |
|---|
| 144 | title = "Direction" |
|---|
| 145 | value = subElement.get("value") |
|---|
| 146 | s = "<h3>%s: <b>%s</b></h3>" % (title, value) |
|---|
| 147 | html.append(s) |
|---|
| 148 | html.append("</div>") |
|---|
| 149 | return html |
|---|
| 150 | |
|---|
| 151 | def _logInputAsString(element): |
|---|
| 152 | s = "<p class=\"testCaseInput\">%s</p>" % (glyphRecordsToHTML(element, False)) |
|---|
| 153 | return [s] |
|---|
| 154 | |
|---|
| 155 | def _logResultAsString(element, showPositions): |
|---|
| 156 | s = "<p class=\"testCaseResult\">%s</p>" % (glyphRecordsToHTML(element, showPositions)) |
|---|
| 157 | return [s] |
|---|
| 158 | |
|---|
| 159 | def _logExpectedResultAsString(element, showPositions): |
|---|
| 160 | if element.get("passed") == "True": |
|---|
| 161 | c = "testCaseExpectedResultPassed" |
|---|
| 162 | else: |
|---|
| 163 | c = "testCaseExpectedResultFailed" |
|---|
| 164 | s = "<p class=\"%s\">%s</p>" % (c, glyphRecordsToHTML(element, showPositions)) |
|---|
| 165 | return [s] |
|---|
| 166 | |
|---|
| 167 | def _glyphRecordsToCanvas(element): |
|---|
| 168 | l = [] |
|---|
| 169 | for i in element: |
|---|
| 170 | name = i.get("name") |
|---|
| 171 | xP = i.get("xPlacement") |
|---|
| 172 | if xP == "None": |
|---|
| 173 | xP = 0 |
|---|
| 174 | else: |
|---|
| 175 | xP = int(float(xP)) |
|---|
| 176 | xP = int(xP) |
|---|
| 177 | yP = i.get("yPlacement") |
|---|
| 178 | if yP == "None": |
|---|
| 179 | yP = 0 |
|---|
| 180 | else: |
|---|
| 181 | yP = int(float(yP)) |
|---|
| 182 | xA = i.get("xAdvance") |
|---|
| 183 | if xA == "None": |
|---|
| 184 | xA = 0 |
|---|
| 185 | else: |
|---|
| 186 | xA = int(float(xA)) |
|---|
| 187 | yA = i.get("yAdvance") |
|---|
| 188 | if yA == "None": |
|---|
| 189 | yA = 0 |
|---|
| 190 | else: |
|---|
| 191 | yA = int(float(yA)) |
|---|
| 192 | s = "[\"%s\", %d, %d, %d, %d]" % (name, xP, yP, xA, yA) |
|---|
| 193 | l.append(s) |
|---|
| 194 | return ", ".join(l) |
|---|
| 195 | |
|---|
| 196 | |
|---|
| 197 | class CanvasInstructionsPen(BasePen): |
|---|
| 198 | |
|---|
| 199 | def __init__(self, glyphSet): |
|---|
| 200 | BasePen.__init__(self, glyphSet) |
|---|
| 201 | self.instructions = ["['beginPath']"] |
|---|
| 202 | |
|---|
| 203 | def getInstructions(self): |
|---|
| 204 | if len(self.instructions) > 1: |
|---|
| 205 | return self.instructions |
|---|
| 206 | return [] |
|---|
| 207 | |
|---|
| 208 | def _moveTo(self, (x, y)): |
|---|
| 209 | self.instructions.append("['moveTo', [%d, %d]]" % (x, y)) |
|---|
| 210 | |
|---|
| 211 | def _lineTo(self, (x, y)): |
|---|
| 212 | self.instructions.append("['lineTo', [%d, %d]]" % (x, y)) |
|---|
| 213 | |
|---|
| 214 | def _curveToOne(self, (x1, y1), (x2, y2), (x3, y3)): |
|---|
| 215 | self.instructions.append("['bezierCurveTo', [%d, %d, %d, %d, %d, %d]]" % (x1, y1, x2, y2, x3, y3)) |
|---|
| 216 | |
|---|
| 217 | def _closePath(self): |
|---|
| 218 | self.instructions.append("['closePath']") |
|---|
| 219 | |
|---|
| 220 | def _getCanvasGlyphData(glyphName, glyphSet): |
|---|
| 221 | glyph = glyphSet[glyphName] |
|---|
| 222 | pen = CanvasInstructionsPen(glyphSet) |
|---|
| 223 | glyph.draw(pen) |
|---|
| 224 | instructions = pen.getInstructions() |
|---|
| 225 | instructions.insert(0, str(glyph.width)) |
|---|
| 226 | return "[%s]" % ", ".join(instructions) |
|---|
| 227 | |
|---|