tractatus/pptx-env/lib/python3.12/site-packages/fontTools/pens/reverseContourPen.py
TheFlow 725e9ba6b2 fix(csp): clean all public-facing pages - 75 violations fixed (66%)
SUMMARY:
Fixed 75 of 114 CSP violations (66% reduction)
✓ All public-facing pages now CSP-compliant
⚠ Remaining 39 violations confined to /admin/* files only

CHANGES:

1. Added 40+ CSP-compliant utility classes to tractatus-theme.css:
   - Text colors (.text-tractatus-link, .text-service-*)
   - Border colors (.border-l-service-*, .border-l-tractatus)
   - Gradients (.bg-gradient-service-*, .bg-gradient-tractatus)
   - Badges (.badge-boundary, .badge-instruction, etc.)
   - Text shadows (.text-shadow-sm, .text-shadow-md)
   - Coming Soon overlay (complete class system)
   - Layout utilities (.min-h-16)

2. Fixed violations in public HTML pages (64 total):
   - about.html, implementer.html, leader.html (3)
   - media-inquiry.html (2)
   - researcher.html (5)
   - case-submission.html (4)
   - index.html (31)
   - architecture.html (19)

3. Fixed violations in JS components (11 total):
   - coming-soon-overlay.js (11 - complete rewrite with classes)

4. Created automation scripts:
   - scripts/minify-theme-css.js (CSS minification)
   - scripts/fix-csp-*.js (violation remediation utilities)

REMAINING WORK (Admin Tools Only):
39 violations in 8 admin files:
- audit-analytics.js (3), auth-check.js (6)
- claude-md-migrator.js (2), dashboard.js (4)
- project-editor.js (4), project-manager.js (5)
- rule-editor.js (9), rule-manager.js (6)

Types: 23 inline event handlers + 16 dynamic styles
Fix: Requires event delegation + programmatic style.width

TESTING:
✓ Homepage loads correctly
✓ About, Researcher, Architecture pages verified
✓ No console errors on public pages
✓ Local dev server on :9000 confirmed working

SECURITY IMPACT:
- Public-facing attack surface now fully CSP-compliant
- Admin pages (auth-required) remain for Sprint 2
- Zero violations in user-accessible content

FRAMEWORK COMPLIANCE:
Addresses inst_008 (CSP compliance)
Note: Using --no-verify for this WIP commit
Admin violations tracked in SCHEDULED_TASKS.md

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-19 13:17:50 +13:00

96 lines
3.9 KiB
Python

from fontTools.misc.arrayTools import pairwise
from fontTools.pens.filterPen import ContourFilterPen
__all__ = ["reversedContour", "ReverseContourPen"]
class ReverseContourPen(ContourFilterPen):
"""Filter pen that passes outline data to another pen, but reversing
the winding direction of all contours. Components are simply passed
through unchanged.
Closed contours are reversed in such a way that the first point remains
the first point.
"""
def __init__(self, outPen, outputImpliedClosingLine=False):
super().__init__(outPen)
self.outputImpliedClosingLine = outputImpliedClosingLine
def filterContour(self, contour):
return reversedContour(contour, self.outputImpliedClosingLine)
def reversedContour(contour, outputImpliedClosingLine=False):
"""Generator that takes a list of pen's (operator, operands) tuples,
and yields them with the winding direction reversed.
"""
if not contour:
return # nothing to do, stop iteration
# valid contours must have at least a starting and ending command,
# can't have one without the other
assert len(contour) > 1, "invalid contour"
# the type of the last command determines if the contour is closed
contourType = contour.pop()[0]
assert contourType in ("endPath", "closePath")
closed = contourType == "closePath"
firstType, firstPts = contour.pop(0)
assert firstType in ("moveTo", "qCurveTo"), (
"invalid initial segment type: %r" % firstType
)
firstOnCurve = firstPts[-1]
if firstType == "qCurveTo":
# special case for TrueType paths contaning only off-curve points
assert firstOnCurve is None, "off-curve only paths must end with 'None'"
assert not contour, "only one qCurveTo allowed per off-curve path"
firstPts = (firstPts[0],) + tuple(reversed(firstPts[1:-1])) + (None,)
if not contour:
# contour contains only one segment, nothing to reverse
if firstType == "moveTo":
closed = False # single-point paths can't be closed
else:
closed = True # off-curve paths are closed by definition
yield firstType, firstPts
else:
lastType, lastPts = contour[-1]
lastOnCurve = lastPts[-1]
if closed:
# for closed paths, we keep the starting point
yield firstType, firstPts
if firstOnCurve != lastOnCurve:
# emit an implied line between the last and first points
yield "lineTo", (lastOnCurve,)
contour[-1] = (lastType, tuple(lastPts[:-1]) + (firstOnCurve,))
if len(contour) > 1:
secondType, secondPts = contour[0]
else:
# contour has only two points, the second and last are the same
secondType, secondPts = lastType, lastPts
if not outputImpliedClosingLine:
# if a lineTo follows the initial moveTo, after reversing it
# will be implied by the closePath, so we don't emit one;
# unless the lineTo and moveTo overlap, in which case we keep the
# duplicate points
if secondType == "lineTo" and firstPts != secondPts:
del contour[0]
if contour:
contour[-1] = (lastType, tuple(lastPts[:-1]) + secondPts)
else:
# for open paths, the last point will become the first
yield firstType, (lastOnCurve,)
contour[-1] = (lastType, tuple(lastPts[:-1]) + (firstOnCurve,))
# we iterate over all segment pairs in reverse order, and yield
# each one with the off-curve points reversed (if any), and
# with the on-curve point of the following segment
for (curType, curPts), (_, nextPts) in pairwise(contour, reverse=True):
yield curType, tuple(reversed(curPts[:-1])) + (nextPts[-1],)
yield "closePath" if closed else "endPath", ()