This file is indexed.

/usr/lib/python2.7/dist-packages/reportlab/graphics/renderbase.py is in python-reportlab 3.3.0-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
#Copyright ReportLab Europe Ltd. 2000-2016
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/graphics/renderbase.py

__version__='3.3.0'
__doc__='''Superclass for renderers to factor out common functionality and default implementations.'''

from reportlab.graphics.shapes import *
from reportlab.lib.validators import DerivedValue
from reportlab import rl_config

def inverse(A):
    "For A affine 2D represented as 6vec return 6vec version of A**(-1)"
    # I checked this RGB
    det = float(A[0]*A[3] - A[2]*A[1])
    R = [A[3]/det, -A[1]/det, -A[2]/det, A[0]/det]
    return tuple(R+[-R[0]*A[4]-R[2]*A[5],-R[1]*A[4]-R[3]*A[5]])

def mmult(A, B):
    "A postmultiplied by B"
    # I checked this RGB
    # [a0 a2 a4]    [b0 b2 b4]
    # [a1 a3 a5] *  [b1 b3 b5]
    # [      1 ]    [      1 ]
    #
    return (A[0]*B[0] + A[2]*B[1],
            A[1]*B[0] + A[3]*B[1],
            A[0]*B[2] + A[2]*B[3],
            A[1]*B[2] + A[3]*B[3],
            A[0]*B[4] + A[2]*B[5] + A[4],
            A[1]*B[4] + A[3]*B[5] + A[5])


def getStateDelta(shape):
    """Used to compute when we need to change the graphics state.
    For example, if we have two adjacent red shapes we don't need
    to set the pen color to red in between. Returns the effect
    the given shape would have on the graphics state"""
    delta = {}
    for prop, value in shape.getProperties().items():
        if prop in STATE_DEFAULTS:
            delta[prop] = value
    return delta


class StateTracker:
    """Keeps a stack of transforms and state
    properties.  It can contain any properties you
    want, but the keys 'transform' and 'ctm' have
    special meanings.  The getCTM()
    method returns the current transformation
    matrix at any point, without needing to
    invert matrixes when you pop."""
    def __init__(self, defaults=None):
        # one stack to keep track of what changes...
        self._deltas = []

        # and another to keep track of cumulative effects.  Last one in
        # list is the current graphics state.  We put one in to simplify
        # loops below.
        self._combined = []
        if defaults is None:
            defaults = STATE_DEFAULTS.copy()
        #ensure  that if we have a transform, we have a CTM
        if 'transform' in defaults:
            defaults['ctm'] = defaults['transform']
        self._combined.append(defaults)

    def push(self,delta):
        """Take a new state dictionary of changes and push it onto
        the stack.  After doing this, the combined state is accessible
        through getState()"""

        newstate = self._combined[-1].copy()
        for key, value in delta.items():
            if key == 'transform':  #do cumulative matrix
                newstate['transform'] = delta['transform']
                newstate['ctm'] = mmult(self._combined[-1]['ctm'], delta['transform'])
                #print 'statetracker transform = (%0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f)' % tuple(newstate['transform'])
                #print 'statetracker ctm = (%0.2f, %0.2f, %0.2f, %0.2f, %0.2f, %0.2f)' % tuple(newstate['ctm'])

            else:  #just overwrite it
                newstate[key] = value

        self._combined.append(newstate)
        self._deltas.append(delta)

    def pop(self):
        """steps back one, and returns a state dictionary with the
        deltas to reverse out of wherever you are.  Depending
        on your back end, you may not need the return value,
        since you can get the complete state afterwards with getState()"""
        del self._combined[-1]
        newState = self._combined[-1]
        lastDelta = self._deltas[-1]
        del  self._deltas[-1]
        #need to diff this against the last one in the state
        reverseDelta = {}
        #print 'pop()...'
        for key, curValue in lastDelta.items():
            #print '   key=%s, value=%s' % (key, curValue)
            prevValue = newState[key]
            if prevValue != curValue:
                #print '    state popping "%s"="%s"' % (key, curValue)
                if key == 'transform':
                    reverseDelta[key] = inverse(lastDelta['transform'])
                else:  #just return to previous state
                    reverseDelta[key] = prevValue
        return reverseDelta

    def getState(self):
        "returns the complete graphics state at this point"
        return self._combined[-1]

    def getCTM(self):
        "returns the current transformation matrix at this point"""
        return self._combined[-1]['ctm']

    def __getitem__(self,key):
        "returns the complete graphics state value of key at this point"
        return self._combined[-1][key]

    def __setitem__(self,key,value):
        "sets the complete graphics state value of key to value"
        self._combined[-1][key] = value

def testStateTracker():
    print('Testing state tracker')
    defaults = {'fillColor':None, 'strokeColor':None,'fontName':None, 'transform':[1,0,0,1,0,0]}
    from reportlab.graphics.shapes import _baseGFontName
    deltas = [
        {'fillColor':'red'},
        {'fillColor':'green', 'strokeColor':'blue','fontName':_baseGFontName},
        {'transform':[0.5,0,0,0.5,0,0]},
        {'transform':[0.5,0,0,0.5,2,3]},
        {'strokeColor':'red'}
        ]

    st = StateTracker(defaults)
    print('initial:', st.getState())
    print()
    for delta in deltas:
        print('pushing:', delta)
        st.push(delta)
        print('state:  ',st.getState(),'\n')

    for delta in deltas:
        print('popping:',st.pop())
        print('state:  ',st.getState(),'\n')


def _expandUserNode(node,canvas):
    if isinstance(node, UserNode):
        try:
            if hasattr(node,'_canvas'):
                ocanvas = 1
            else:
                node._canvas = canvas
                ocanvas = None
            onode = node
            node = node.provideNode()
        finally:
            if not ocanvas: del onode._canvas
    return node

def renderScaledDrawing(d):
    renderScale = d.renderScale
    if renderScale!=1.0:
        o = d
        d = d.__class__(o.width*renderScale,o.height*renderScale)
        d.__dict__ = o.__dict__.copy()
        d.scale(renderScale,renderScale)
        d.renderScale = 1.0
    return d

class Renderer:
    """Virtual superclass for graphics renderers."""

    def __init__(self):
        self._tracker = StateTracker()
        self._nodeStack = []   #track nodes visited

    def undefined(self, operation):
        raise ValueError("%s operation not defined at superclass class=%s" %(operation, self.__class__))

    def draw(self, drawing, canvas, x=0, y=0, showBoundary=rl_config._unset_):
        """This is the top level function, which draws the drawing at the given
        location. The recursive part is handled by drawNode."""
        #stash references for ease of  communication
        if showBoundary is rl_config._unset_: showBoundary=rl_config.showBoundary
        self._canvas = canvas
        canvas.__dict__['_drawing'] = self._drawing = drawing
        drawing._parent = None
        try:
            #bounding box
            if showBoundary: canvas.rect(x, y, drawing.width, drawing.height)
            canvas.saveState()
            self.initState(x,y)  #this is the push()
            self.drawNode(drawing)
            self.pop()
            canvas.restoreState()
        finally:
            #remove any circular references
            del self._canvas, self._drawing, canvas._drawing, drawing._parent

    def initState(self,x,y):
        deltas = STATE_DEFAULTS.copy()
        deltas['transform'] = [1,0,0,1,x,y]
        self._tracker.push(deltas)
        self.applyStateChanges(deltas, {})

    def pop(self):
        self._tracker.pop()

    def drawNode(self, node):
        """This is the recursive method called for each node
        in the tree"""
        # Undefined here, but with closer analysis probably can be handled in superclass
        self.undefined("drawNode")

    def getStateValue(self, key):
        """Return current state parameter for given key"""
        currentState = self._tracker._combined[-1]
        return currentState[key]
    
    def fillDerivedValues(self, node):
        """Examine a node for any values which are Derived,
        and replace them with their calculated values.
        Generally things may look at the drawing or their
        parent.
        
        """
        for key, value in node.__dict__.items():
            if isinstance(value, DerivedValue):
                #just replace with default for key?
                #print '    fillDerivedValues(%s)' % key
                newValue = value.getValue(self, key)
                #print '   got value of %s' % newValue
                node.__dict__[key] = newValue

    def drawNodeDispatcher(self, node):
        """dispatch on the node's (super) class: shared code"""

        canvas = getattr(self,'_canvas',None)
        # replace UserNode with its contents

        try:
            node = _expandUserNode(node,canvas)
            if not node: return
            if hasattr(node,'_canvas'):
                ocanvas = 1
            else:
                node._canvas = canvas
                ocanvas = None

            self.fillDerivedValues(node)
            dtcb = getattr(node,'_drawTimeCallback',None)
            if dtcb:
                dtcb(node,canvas=canvas,renderer=self)
            #draw the object, or recurse
            if isinstance(node, Line):
                self.drawLine(node)
            elif isinstance(node, Image):
                self.drawImage(node)
            elif isinstance(node, Rect):
                self.drawRect(node)
            elif isinstance(node, Circle):
                self.drawCircle(node)
            elif isinstance(node, Ellipse):
                self.drawEllipse(node)
            elif isinstance(node, PolyLine):
                self.drawPolyLine(node)
            elif isinstance(node, Polygon):
                self.drawPolygon(node)
            elif isinstance(node, Path):
                self.drawPath(node)
            elif isinstance(node, String):
                self.drawString(node)
            elif isinstance(node, Group):
                self.drawGroup(node)
            elif isinstance(node, Wedge):
                self.drawWedge(node)
            else:
                print('DrawingError','Unexpected element %s in drawing!' % str(node))
        finally:
            if not ocanvas: del node._canvas

    _restores = {'stroke':'_stroke','stroke_width': '_lineWidth','stroke_linecap':'_lineCap',
                'stroke_linejoin':'_lineJoin','fill':'_fill','font_family':'_font',
                'font_size':'_fontSize'}

    def drawGroup(self, group):
        # just do the contents.  Some renderers might need to override this
        # if they need a flipped transform
        canvas = getattr(self,'_canvas',None)
        for node in group.getContents():
            node = _expandUserNode(node,canvas)
            if not node: continue

            #here is where we do derived values - this seems to get everything. Touch wood.            
            self.fillDerivedValues(node)
            try:
                if hasattr(node,'_canvas'):
                    ocanvas = 1
                else:
                    node._canvas = canvas
                    ocanvas = None
                node._parent = group
                self.drawNode(node)
            finally:
                del node._parent
                if not ocanvas: del node._canvas

    def drawWedge(self, wedge):
        # by default ask the wedge to make a polygon of itself and draw that!
        #print "drawWedge"
        P = wedge.asPolygon()
        if isinstance(P,Path):
            self.drawPath(P)
        else:
            self.drawPolygon(P)

    def drawPath(self, path):
        polygons = path.asPolygons()
        for polygon in polygons:
                self.drawPolygon(polygon)

    def drawRect(self, rect):
        # could be implemented in terms of polygon
        self.undefined("drawRect")

    def drawLine(self, line):
        self.undefined("drawLine")

    def drawCircle(self, circle):
        self.undefined("drawCircle")

    def drawPolyLine(self, p):
        self.undefined("drawPolyLine")

    def drawEllipse(self, ellipse):
        self.undefined("drawEllipse")

    def drawPolygon(self, p):
        self.undefined("drawPolygon")

    def drawString(self, stringObj):
        self.undefined("drawString")

    def applyStateChanges(self, delta, newState):
        """This takes a set of states, and outputs the operators
        needed to set those properties"""
        self.undefined("applyStateChanges")

if __name__=='__main__':
    print("this file has no script interpretation")
    print(__doc__)