Fix clipping, considering that the clip path depends on the current painter transform, therefore the order of updateState() operations matters. So only track if the clip has been updated and always re-apply if it has.

This commit is contained in:
Kovid Goyal 2013-01-08 14:15:06 +05:30
parent d5e9c105ab
commit 6d1a9dcc29

View File

@ -11,7 +11,7 @@ from math import sqrt
from collections import namedtuple from collections import namedtuple
from PyQt4.Qt import ( from PyQt4.Qt import (
QBrush, QPen, Qt, QPointF, QTransform, QPainterPath, QPaintEngine, QImage) QBrush, QPen, Qt, QPointF, QTransform, QPaintEngine, QImage)
from calibre.ebooks.pdf.render.common import ( from calibre.ebooks.pdf.render.common import (
Name, Array, fmtnum, Stream, Dictionary) Name, Array, fmtnum, Stream, Dictionary)
@ -248,7 +248,7 @@ class TexturePattern(TilingPattern):
class GraphicsState(object): class GraphicsState(object):
FIELDS = ('fill', 'stroke', 'opacity', 'transform', 'brush_origin', FIELDS = ('fill', 'stroke', 'opacity', 'transform', 'brush_origin',
'clip', 'do_fill', 'do_stroke') 'clip_updated', 'do_fill', 'do_stroke')
def __init__(self): def __init__(self):
self.fill = QBrush() self.fill = QBrush()
@ -256,7 +256,7 @@ class GraphicsState(object):
self.opacity = 1.0 self.opacity = 1.0
self.transform = QTransform() self.transform = QTransform()
self.brush_origin = QPointF() self.brush_origin = QPointF()
self.clip = QPainterPath() self.clip_updated = False
self.do_fill = False self.do_fill = False
self.do_stroke = True self.do_stroke = True
self.qt_pattern_cache = {} self.qt_pattern_cache = {}
@ -274,7 +274,7 @@ class GraphicsState(object):
ans.opacity = self.opacity ans.opacity = self.opacity
ans.transform = self.transform * QTransform() ans.transform = self.transform * QTransform()
ans.brush_origin = QPointF(self.brush_origin) ans.brush_origin = QPointF(self.brush_origin)
ans.clip = self.clip ans.clip_updated = self.clip_updated
ans.do_fill, ans.do_stroke = self.do_fill, self.do_stroke ans.do_fill, ans.do_stroke = self.do_fill, self.do_stroke
return ans return ans
@ -311,7 +311,7 @@ class Graphics(object):
s.opacity = state.opacity() s.opacity = state.opacity()
if flags & QPaintEngine.DirtyClipPath or flags & QPaintEngine.DirtyClipRegion: if flags & QPaintEngine.DirtyClipPath or flags & QPaintEngine.DirtyClipRegion:
s.clip = painter.clipPath() s.clip_updated = True
def reset(self): def reset(self):
self.current_state = GraphicsState() self.current_state = GraphicsState()
@ -326,7 +326,7 @@ class Graphics(object):
ps = self.pending_state ps = self.pending_state
pdf = self.pdf pdf = self.pdf
if (ps.transform != pdf_state.transform or ps.clip != pdf_state.clip): if ps.transform != pdf_state.transform or ps.clip_updated:
pdf.restore_stack() pdf.restore_stack()
pdf.save_stack() pdf.save_stack()
pdf_state = self.base_state pdf_state = self.base_state
@ -341,11 +341,14 @@ class Graphics(object):
pdf_state.brush_origin != ps.brush_origin): pdf_state.brush_origin != ps.brush_origin):
self.apply_fill(ps, pdf_system, painter) self.apply_fill(ps, pdf_system, painter)
if (pdf_state.clip != ps.clip): if ps.clip_updated:
p = convert_path(ps.clip) ps.clip_updated = False
fill_rule = {Qt.OddEvenFill:'evenodd', path = painter.clipPath()
Qt.WindingFill:'winding'}[ps.clip.fillRule()] if not path.isEmpty():
pdf.add_clip(p, fill_rule=fill_rule) p = convert_path(path)
fill_rule = {Qt.OddEvenFill:'evenodd',
Qt.WindingFill:'winding'}[path.fillRule()]
pdf.add_clip(p, fill_rule=fill_rule)
self.current_state = self.pending_state self.current_state = self.pending_state
self.pending_state = None self.pending_state = None