Module: Postsvg::Translation::Handlers::Shared

Included in:
CircleHandler, EllipseHandler, GroupHandler, ImageHandler, LineHandler, PathHandler, PolygonHandler, PolylineHandler, RectHandler, SvgHandler, TextHandler
Defined in:
lib/postsvg/translation/handlers/shared.rb

Overview

Helpers shared by every handler. Mixed into each handler class via extend Shared so handler bodies stay declarative.

All element classes in Svg::Elements provide fill, stroke_paint, stroke, and transform getters (returning nil when not applicable). This module relies on those getters existing — no respond_to? checks.

Instance Method Summary collapse

Instance Method Details

#emit_fill(element, context) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/postsvg/translation/handlers/shared.rb', line 53

def emit_fill(element, context)
  paint = element.fill
  return unless paint && paint.color?

  color = paint.value
  if color.gray?
    context.emitter.emit(Model::Operators::Color::Setgray.new(gray: color.gray_level))
  else
    context.emitter.emit(Model::Operators::Color::Setrgbcolor.new(
      red: color.red / 255.0, green: color.green / 255.0, blue: color.blue / 255.0,
    ))
  end
end

#emit_paint(element, context) ⇒ Object

Emit paint setup + paint terminator(s) for an element. When the element has only fill, emits color + fill. When only stroke, emits color + stroke. When both, emits a gsave / setrgbcolor(fill) / fill / grestore / setrgbcolor(stroke) / stroke sequence so each paint uses the right color.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/postsvg/translation/handlers/shared.rb', line 20

def emit_paint(element, context)
  fill_paint = element.fill
  stroke_paint = element.stroke_paint
  fill_on = fill_paint && fill_paint.color?
  stroke_on = stroke_paint && stroke_paint.color?

  if fill_on && stroke_on
    emit_fill(element, context)
    context.emitter.emit(Model::Operators::GraphicsState::Gsave.new)
    context.emitter.emit(Model::Operators::Painting::Fill.new)
    context.emitter.emit(Model::Operators::GraphicsState::Grestore.new)
    emit_stroke(element, context)
    context.emitter.emit(Model::Operators::Painting::Stroke.new)
  elsif fill_on
    emit_fill(element, context)
    context.emitter.emit(Model::Operators::Painting::Fill.new)
  elsif stroke_on
    emit_stroke(element, context)
    context.emitter.emit(Model::Operators::Painting::Stroke.new)
  else
    # No explicit paint — fill with current color (default).
    context.emitter.emit(Model::Operators::Painting::Fill.new)
  end
end

#emit_paint_setup(element, context) ⇒ Object

Convenience for handlers that want to set up colors without emitting a paint terminator (e.g. LineHandler which always strokes).



48
49
50
51
# File 'lib/postsvg/translation/handlers/shared.rb', line 48

def emit_paint_setup(element, context)
  emit_fill(element, context)
  emit_stroke(element, context)
end

#emit_stroke(element, context) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/postsvg/translation/handlers/shared.rb', line 67

def emit_stroke(element, context)
  paint = element.stroke_paint
  return unless paint && paint.color?

  color = paint.value
  context.emitter.emit(Model::Operators::Color::Setrgbcolor.new(
    red: color.red / 255.0, green: color.green / 255.0, blue: color.blue / 255.0,
  ))
  stroke = element.stroke
  return unless stroke

  context.emitter.emit(Model::Operators::GraphicsState::Setlinewidth.new(width: stroke.width)) if stroke.width
  if stroke.linecap
    code = { butt: 0, round: 1, square: 2 }[stroke.linecap.to_sym]
    context.emitter.emit(Model::Operators::GraphicsState::Setlinecap.new(cap_code: code)) if code
  end
  if stroke.linejoin
    code = { miter: 0, round: 1, bevel: 2 }[stroke.linejoin.to_sym]
    context.emitter.emit(Model::Operators::GraphicsState::Setlinejoin.new(join_code: code)) if code
  end
end

#emit_transform(element, context) ⇒ Object



89
90
91
92
93
94
95
96
97
98
# File 'lib/postsvg/translation/handlers/shared.rb', line 89

def emit_transform(element, context)
  transform = element.transform
  return unless transform && !transform.empty?

  transform.matrices.each do |matrix|
    context.emitter.emit(Model::Operators::Transformations::Concat.new(matrix: [
      matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f,
    ]))
  end
end

#expand_bbox(context, *points) ⇒ Object



100
101
102
103
104
105
106
# File 'lib/postsvg/translation/handlers/shared.rb', line 100

def expand_bbox(context, *points)
  xs = points.each_slice(2).map(&:first)
  ys = points.each_slice(2).map(&:last)
  return if xs.empty?

  context.expand_bbox!((xs.min..xs.max), (ys.min..ys.max))
end