Module: NSWTopo::Font::Chrome

Defined in:
lib/nswtopo/font/chrome.rb

Constant Summary collapse

ATTRIBUTES =
%w[font-family font-variant font-style font-weight font-size letter-spacing word-spacing]

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(instance) ⇒ Object



31
32
33
# File 'lib/nswtopo/font/chrome.rb', line 31

def self.extended(instance)
  instance.start_chrome
end

Instance Method Details

#command(string) ⇒ Object



6
7
8
9
10
11
12
13
14
# File 'lib/nswtopo/font/chrome.rb', line 6

def command(string)
  @input.puts string
  lines, match = @output.expect(/(\{.*)\n/, 1)
  response = JSON.parse match
  raise "unexpected chrome error: %s" % response.dig("exceptionDetails", "exception", "description") if response["exceptionDetails"]
  response.fetch("result").dig("value")
rescue TypeError, JSON::ParserError, KeyError
  raise "unexpected chrome error"
end

#glyph_length(string, attributes) ⇒ Object



47
48
49
50
51
52
53
54
55
56
# File 'lib/nswtopo/font/chrome.rb', line 47

def glyph_length(string, attributes)
  style = attributes.slice(*ATTRIBUTES).map do |pair|
    pair.join ?:
  end.join(?;)
  style << ";white-space:pre" if ?\s == string
  validate attributes["font-family"]
  command %Q[text.setAttribute("style", #{style.inspect})]
  command %Q[text.textContent=#{string.inspect}]
  command(%Q[text.getBoundingClientRect().width]) / @mm
end

#start_chromeObject



16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/nswtopo/font/chrome.rb', line 16

def start_chrome
  chrome_path = Config["chrome"]
  svg = <<~XML
    <?xml version='1.0' encoding='UTF-8'?>
    <svg version='1.1' baseProfile='full' xmlns='http://www.w3.org/2000/svg' width='1mm' height='1mm' viewBox='0 0 1 1'>
      <rect id='mm' width='1' height='1' stroke='none' />
      <text id='text' />
    </svg>
  XML
  @output, @input, @pid = PTY.spawn chrome_path, "--headless", "--disable-gpu", "--repl", "data:image/svg+xml;base64,#{Base64.encode64 svg}"
  ObjectSpace.define_finalizer self, Proc.new { @input.puts "quit" }
  command %Q[text = document.getElementById("text")]
  @mm = command %Q[document.getElementById("mm").getBoundingClientRect().width]
end

#validate(family) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
# File 'lib/nswtopo/font/chrome.rb', line 35

def validate(family)
  return unless family
  @families ||= Set[]
  @families.add?(family) || return
  command %Q[text.textContent="abcdefghijklmnopqrstuvwxyz"]
  ["font-family:#{family}", nil].map do |style|
    command %Q[text.setAttribute("style", "#{style}")]
    command %Q[text.getBoundingClientRect().width]
  end.inject(&:==) || return
  log_neutral "font '#{family}' doesn't appear to be available"
end