|
@ -1,14 +0,0 @@
|
|||
FROM ubuntu:14.04
|
||||
MAINTAINER xymostech <xymostech@gmail.com>
|
||||
RUN apt-get -qq update
|
||||
RUN apt-get -qqy install default-jre=2:1.7-51 firefox=28.0+build2-0ubuntu2 xvfb=2:1.15.1-0ubuntu2 wget=1.15-1ubuntu1 python=2.7.5-5ubuntu3 python-pip=1.5.4-1 nodejs=0.10.25~dfsg2-2ubuntu1 || true
|
||||
RUN wget http://selenium-release.storage.googleapis.com/2.43/selenium-server-standalone-2.43.0.jar
|
||||
RUN ln -s /usr/bin/nodejs /usr/bin/node
|
||||
RUN pip install selenium pypng
|
||||
ENV DISPLAY :1
|
||||
CMD /bin/bash ~/run.sh
|
||||
RUN echo "java -jar /selenium-server-standalone-2.43.0.jar > /dev/null &" >> ~/run.sh
|
||||
RUN echo "Xvfb :1 2> /dev/null &" >> ~/run.sh
|
||||
RUN echo "make -C /KaTeX serve > /dev/null &" >> ~/run.sh
|
||||
RUN echo "sleep 2" >> ~/run.sh
|
||||
RUN echo "/KaTeX/dockers/Screenshotter/screenshotter.py /KaTeX/test/screenshotter/ss_data.json" >> ~/run.sh
|
|
@ -1,29 +1,67 @@
|
|||
### How to generate screenshotter images
|
||||
----------------------------------------
|
||||
# How to generate screenshotter images
|
||||
|
||||
## Automatic generation of screen shots
|
||||
|
||||
Now you too can generate screenshots from your own computer, and (hopefully)
|
||||
have them look mostly the same as the current ones! To start, make a docker
|
||||
image from the included Dockerfile using a command like
|
||||
have them look mostly the same as the current ones! Make sure you have docker
|
||||
installed and running. Also make sure that the development server is running,
|
||||
or start it by running
|
||||
|
||||
docker build --tag=ss .
|
||||
node server.js
|
||||
|
||||
from within this directory (note you need to have docker installed and running
|
||||
for this to work). This will build a docker image with the `ss` tag, which you
|
||||
can then use to run dockers based on it.
|
||||
in the top level directory of the source tree. If all you want is (re)create
|
||||
all the snapshots for all the browsers, then you can do so by running the
|
||||
`screenshotter.sh` script:
|
||||
|
||||
This Dockerfile is set up such that it will run everything and generate all the
|
||||
screenshots when the docker is run, so no interactive input is required. All
|
||||
that you need to do is mount the KaTeX directory you want to test into the
|
||||
`/KaTeX` directory in the docker, and run the `ss` docker, like so:
|
||||
dockers/Screenshotter/screenshotter.sh
|
||||
|
||||
docker run --volume=/your/KaTeX/:/KaTeX ss
|
||||
It will fetch all required selenium docker images, and use them to
|
||||
take screenshots.
|
||||
|
||||
The `--volume=/your/KaTeX:/KaTeX` switch mounts your KaTeX directory into the
|
||||
docker. Note this is a read-write mounting, so the new screenshots will be
|
||||
directly placed into your KaTeX directory.
|
||||
## Manual generation
|
||||
|
||||
Since this docker is very self-contained, there should be no need to do
|
||||
interactive management of the docker, but if you feel the need, you can read the
|
||||
General Docker Help section of the MathJaxFonts docker readme.
|
||||
If you are creating screenshots on a regular basis, you can keep the
|
||||
docker containers with the selenium setups running. Essentially you
|
||||
are encouraged to reproduce the steps from `screenshotter.sh`
|
||||
manually. Example run for Firefox:
|
||||
|
||||
That's it!
|
||||
container=$(docker run -d -P selenium/standalone-firefox:2.46.0)
|
||||
node dockers/Screenshotter/screenshotter.js -b firefox -c ${container}
|
||||
# possibly repeat the above command as often as you need, then eventually
|
||||
docker stop ${container}
|
||||
docker rm ${container}
|
||||
|
||||
For Chrome, simply replace both occurrences of `firefox` with `chrome`.
|
||||
|
||||
## Use without docker
|
||||
|
||||
It is possible to run `screenshotter.js` without the use of Docker:
|
||||
|
||||
npm install selenium-webdriver
|
||||
node dockers/Screenshotter/screenshotter.js
|
||||
|
||||
This will generate screenshots using the Firefox installed on your system.
|
||||
Browsers other than Firefox can be targeted using the `--browser` option.
|
||||
For a complete list of options pass `--help` as an argument to
|
||||
`screenshotter.js`. Using these it should be possible to have the script
|
||||
connect to almost any Selenium web driver you might have access to.
|
||||
|
||||
Note that screenshots taken without Docker are very likely to disagree
|
||||
from the ones stored in the repository, due to different versions of
|
||||
various software components being used. The screenshots taken in this
|
||||
fashion are well suited for visual inspection, but for exact binary
|
||||
comparisons it would be neccessary to carefully set up the environment
|
||||
to match the one used by the Docker approach.
|
||||
|
||||
## Choosing the list of test cases
|
||||
|
||||
Both `screenshotter.js` and `screenshotter.sh` will accept
|
||||
an `--include` option (short `-i`) which can be used to specify
|
||||
a list of test cases to be processed, as a comma separated list.
|
||||
Conversely, the `--exclude` option (short `-x`) can be used
|
||||
to specify a list of cases which are not being processed.
|
||||
|
||||
Examples:
|
||||
|
||||
node dockers/Screenshotter/screenshotter.js -i Sqrt,SqrtRoot
|
||||
dockers/Screenshotter/screenshotter.sh --exclude=GreekLetters
|
||||
|
|
237
dockers/Screenshotter/screenshotter.js
Normal file
|
@ -0,0 +1,237 @@
|
|||
"use strict";
|
||||
|
||||
var childProcess = require("child_process");
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var net = require("net");
|
||||
var selenium = require("selenium-webdriver");
|
||||
|
||||
var data = require("../../test/screenshotter/ss_data.json");
|
||||
|
||||
var dstDir = path.normalize(
|
||||
path.join(__dirname, "..", "..", "test", "screenshotter", "images"));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Process command line arguments
|
||||
|
||||
var opts = require("nomnom")
|
||||
.option("browser", {
|
||||
abbr: "b",
|
||||
"default": "firefox",
|
||||
help: "Name of the browser to use"
|
||||
})
|
||||
.option("container", {
|
||||
abbr: "c",
|
||||
type: "string",
|
||||
help: "Name or ID of a running docker container to contact"
|
||||
})
|
||||
.option("seleniumURL", {
|
||||
full: "selenium-url",
|
||||
help: "Full URL of the Selenium web driver"
|
||||
})
|
||||
.option("seleniumIP", {
|
||||
full: "selenium-ip",
|
||||
help: "IP address of the Selenium web driver"
|
||||
})
|
||||
.option("seleniumPort", {
|
||||
full: "selenium-port",
|
||||
"default": 4444,
|
||||
help: "Port number of the Selenium web driver"
|
||||
})
|
||||
.option("katexURL", {
|
||||
full: "katex-url",
|
||||
help: "Full URL of the KaTeX development server"
|
||||
})
|
||||
.option("katexIP", {
|
||||
full: "katex-ip",
|
||||
"default": "localhost",
|
||||
help: "Full URL of the KaTeX development server"
|
||||
})
|
||||
.option("katexPort", {
|
||||
full: "katex-port",
|
||||
"default": 7936,
|
||||
help: "Port number of the KaTeX development server"
|
||||
})
|
||||
.option("include", {
|
||||
abbr: "i",
|
||||
help: "Comma-separated list of test cases to process"
|
||||
})
|
||||
.option("exclude", {
|
||||
abbr: "x",
|
||||
help: "Comma-separated list of test cases to exclude"
|
||||
})
|
||||
.parse();
|
||||
|
||||
var listOfCases;
|
||||
if (opts.include) {
|
||||
listOfCases = opts.include.split(",");
|
||||
} else {
|
||||
listOfCases = Object.keys(data);
|
||||
}
|
||||
if (opts.exclude) {
|
||||
var exclude = opts.exclude.split(",");
|
||||
listOfCases = listOfCases.filter(function(key) {
|
||||
return exclude.indexOf(key) === -1;
|
||||
});
|
||||
}
|
||||
|
||||
var seleniumURL = opts.seleniumURL;
|
||||
var katexURL = opts.katexURL;
|
||||
var seleniumIP = opts.seleniumIP;
|
||||
var seleniumPort = opts.seleniumPort;
|
||||
var katexIP = opts.katexIP;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Work out connection to selenium docker container
|
||||
|
||||
function check(err) {
|
||||
if (!err) {
|
||||
return;
|
||||
}
|
||||
console.error(err);
|
||||
console.error(err.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function dockerCmd() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
return childProcess.execFileSync(
|
||||
"docker", args, { encoding: "utf-8" }).replace(/\n$/, "");
|
||||
}
|
||||
|
||||
if (!seleniumURL && opts.container) {
|
||||
try {
|
||||
// When using boot2docker, seleniumIP and katexIP are distinct.
|
||||
seleniumIP = childProcess.execFileSync(
|
||||
"boot2docker", ["ip"], { encoding: "utf-8" }).replace(/\n$/, "");
|
||||
var config = childProcess.execFileSync(
|
||||
"boot2docker", ["config"], { encoding: "utf-8" });
|
||||
config = (/^HostIP = "(.*)"$/m).exec(config);
|
||||
if (!config) {
|
||||
console.error("Failed to find HostIP");
|
||||
process.exit(2);
|
||||
}
|
||||
katexIP = config[1];
|
||||
} catch(e) {
|
||||
seleniumIP = katexIP = dockerCmd(
|
||||
"inspect", "-f", "{{.NetworkSettings.Gateway}}", opts.container);
|
||||
}
|
||||
seleniumPort = dockerCmd("port", opts.container, seleniumPort);
|
||||
seleniumPort = seleniumPort.replace(/^.*:/, "");
|
||||
}
|
||||
if (!seleniumURL && seleniumIP) {
|
||||
seleniumURL = "http://" + seleniumIP + ":" + seleniumPort + "/wd/hub";
|
||||
}
|
||||
if (seleniumURL) {
|
||||
console.log("Selenium driver at " + seleniumURL);
|
||||
} else {
|
||||
console.log("Selenium driver in local session");
|
||||
}
|
||||
|
||||
if (!katexURL) {
|
||||
katexURL = "http://" + katexIP + ":" + opts.katexPort + "/";
|
||||
}
|
||||
var toStrip = "http://localhost:7936/"; // remove this from testcase URLs
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Wait for container to become ready
|
||||
|
||||
var attempts = 0;
|
||||
process.nextTick(seleniumIP ? tryConnect : buildDriver);
|
||||
function tryConnect() {
|
||||
var sock = net.connect({
|
||||
host: seleniumIP,
|
||||
port: +seleniumPort
|
||||
});
|
||||
sock.on("connect", function() {
|
||||
sock.end();
|
||||
attempts = 0;
|
||||
setTimeout(buildDriver, 0);
|
||||
}).on("error", function() {
|
||||
if (++attempts > 50) {
|
||||
throw new Error("Failed to connect selenium server.");
|
||||
}
|
||||
setTimeout(tryConnect, 200);
|
||||
});
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Build the web driver
|
||||
|
||||
var driver;
|
||||
function buildDriver() {
|
||||
var builder = new selenium.Builder().forBrowser(opts.browser);
|
||||
if (seleniumURL) {
|
||||
builder.usingServer(seleniumURL);
|
||||
}
|
||||
driver = builder.build();
|
||||
setSize(targetW, targetH);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Set the screen size
|
||||
|
||||
var targetW = 1024, targetH = 768;
|
||||
function setSize(reqW, reqH) {
|
||||
return driver.manage().window().setSize(reqW, reqH).then(function() {
|
||||
return driver.takeScreenshot();
|
||||
}).then(function(img) {
|
||||
img = imageDimensions(img);
|
||||
var actualW = img.width;
|
||||
var actualH = img.height;
|
||||
if (actualW === targetW && actualH === targetH) {
|
||||
process.nextTick(takeScreenshots);
|
||||
return;
|
||||
}
|
||||
if (++attempts > 5) {
|
||||
throw new Error("Failed to set window size correctly.");
|
||||
}
|
||||
return setSize(targetW + reqW - actualW, targetH + reqH - actualH);
|
||||
}, check);
|
||||
}
|
||||
|
||||
function imageDimensions(img) {
|
||||
var buf = new Buffer(img, "base64");
|
||||
return {
|
||||
buf: buf,
|
||||
width: buf.readUInt32BE(16),
|
||||
height: buf.readUInt32BE(20)
|
||||
};
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Take the screenshots
|
||||
|
||||
function takeScreenshots() {
|
||||
listOfCases.forEach(takeScreenshot);
|
||||
}
|
||||
|
||||
function takeScreenshot(key) {
|
||||
var url = data[key];
|
||||
if (!url) {
|
||||
console.error("Test case " + key + " not known!");
|
||||
return;
|
||||
}
|
||||
url = katexURL + url.substr(toStrip.length);
|
||||
driver.get(url);
|
||||
driver.takeScreenshot().then(function haveScreenshot(img) {
|
||||
img = imageDimensions(img);
|
||||
if (img.width !== targetW || img.height !== targetH) {
|
||||
throw new Error("Excpected " + targetW + " x " + targetH +
|
||||
", got " + img.width + "x" + img.height);
|
||||
}
|
||||
if (key === "Lap" && opts.browser === "firefox" &&
|
||||
img.buf[0x32] === 0xf8) {
|
||||
/* There is some strange non-determinism with this case,
|
||||
* causing slight vertical shifts. The first difference
|
||||
* is at offset 0x32, where one file has byte 0xf8 and
|
||||
* the other has something else. By using a different
|
||||
* output file name for one of these cases, we accept both.
|
||||
*/
|
||||
key += "_alt";
|
||||
}
|
||||
var file = path.join(dstDir, key + "-" + opts.browser + ".png");
|
||||
fs.writeFile(file, img.buf, check);
|
||||
console.log(key);
|
||||
}, check);
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import png
|
||||
import StringIO
|
||||
import sys
|
||||
|
||||
from selenium import webdriver
|
||||
|
||||
|
||||
def get_png_size(png_data):
|
||||
w, h, _, _ = png.Reader(file=StringIO.StringIO(png_data)).read()
|
||||
return (w, h)
|
||||
|
||||
|
||||
def set_driver_size(driver, width, height):
|
||||
"""Correctly sets the size of the driver window so screenshots end up the
|
||||
provided size"""
|
||||
driver.set_window_size(width, height)
|
||||
|
||||
screenshot_size = get_png_size(driver.get_screenshot_as_png())
|
||||
attempts = 0
|
||||
while (width, height) != screenshot_size:
|
||||
attempts += 1
|
||||
if attempts > 5:
|
||||
print "Tried 5 times to size screen correctly, bailing out"
|
||||
exit(1)
|
||||
|
||||
ss_width, ss_height = screenshot_size
|
||||
driver.set_window_size(
|
||||
width + (width - ss_width),
|
||||
height + (height - ss_height))
|
||||
screenshot_size = get_png_size(driver.get_screenshot_as_png())
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Take screenshots of webpages', add_help=False)
|
||||
parser.add_argument('file', metavar='file.json')
|
||||
parser.add_argument('-t', '--tests', metavar='test', nargs='*')
|
||||
parser.add_argument('-w', '--width', metavar='width', default=1024,
|
||||
type=int)
|
||||
parser.add_argument('-h', '--height', metavar='height', default=768,
|
||||
type=int)
|
||||
parser.add_argument('-b', '--browser', metavar='browser',
|
||||
choices=['firefox'], default='firefox')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
data = None
|
||||
with open(args.file) as f:
|
||||
try:
|
||||
data = json.load(f)
|
||||
except ValueError:
|
||||
print "Invalid json in input file:", args.file
|
||||
exit(1)
|
||||
|
||||
tests = []
|
||||
|
||||
if args.tests is None:
|
||||
tests = data.keys()
|
||||
else:
|
||||
data_tests = data.keys()
|
||||
for test in args.tests:
|
||||
if test not in data_tests:
|
||||
print "Unknown test:", test
|
||||
exit(1)
|
||||
|
||||
tests = args.tests
|
||||
|
||||
print "Starting up"
|
||||
sys.stdout.flush()
|
||||
|
||||
driver = None
|
||||
if args.browser == 'firefox':
|
||||
driver = webdriver.Firefox()
|
||||
else:
|
||||
print "Unknown browser:", args.browser
|
||||
exit(1)
|
||||
|
||||
set_driver_size(driver, args.width, args.height)
|
||||
|
||||
data_dir = os.path.join(
|
||||
os.path.dirname(os.path.realpath(args.file)), "images")
|
||||
|
||||
try:
|
||||
os.mkdir(data_dir)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
for test, url in data.iteritems():
|
||||
if test in tests:
|
||||
filename = os.path.join(
|
||||
data_dir, '%s-%s.png' % (test, args.browser))
|
||||
|
||||
print "Running:", test
|
||||
sys.stdout.flush()
|
||||
|
||||
driver.get(url)
|
||||
driver.get_screenshot_as_file(filename)
|
||||
|
||||
print "Done"
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
28
dockers/Screenshotter/screenshotter.sh
Executable file
|
@ -0,0 +1,28 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This script does a one-shot creation of screenshots, creating needed
|
||||
# docker containers and removing them afterwards. During development,
|
||||
# it might be desirable to avoid the overhead for starting and
|
||||
# stopping the containers. Developers are encouraged to manage
|
||||
# suitable containers themselves, calling the screenshotter.js script
|
||||
# directly.
|
||||
|
||||
status=0
|
||||
for browserTag in firefox:2.46.0 chrome:2.46.0; do
|
||||
browser=${browserTag%:*}
|
||||
image=selenium/standalone-${browserTag}
|
||||
echo "Starting container for ${image}"
|
||||
container=$(docker run -d -P ${image})
|
||||
[[ ${container} ]] || continue
|
||||
echo "Container ${container:0:12} started, creating screenshots..."
|
||||
if node "$(dirname "$0")"/screenshotter.js \
|
||||
--browser="${browser}" --container="${container}" "$@"; then
|
||||
res=Done
|
||||
else
|
||||
res=Failed
|
||||
status=1
|
||||
fi
|
||||
echo "${res} taking screenshots, stopping and removing ${container:0:12}"
|
||||
docker stop ${container} >/dev/null && docker rm ${container} >/dev/null
|
||||
done
|
||||
exit ${status}
|
|
@ -20,6 +20,8 @@
|
|||
"jasmine-node": "2.0.0-beta4",
|
||||
"jshint": "^2.5.6",
|
||||
"less": "~1.7.5",
|
||||
"selenium-webdriver": "^2.46.1",
|
||||
"nomnom": "^1.8.1",
|
||||
"uglify-js": "~2.4.15"
|
||||
},
|
||||
"bin": "cli.js",
|
||||
|
|
BIN
test/screenshotter/images/Accents-chrome.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
test/screenshotter/images/Arrays-chrome.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
test/screenshotter/images/Baseline-chrome.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
test/screenshotter/images/BasicTest-chrome.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
test/screenshotter/images/BinomTest-chrome.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
test/screenshotter/images/Colors-chrome.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
test/screenshotter/images/DeepFontSizing-chrome.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
test/screenshotter/images/DelimiterSizing-chrome.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
test/screenshotter/images/DisplayMode-chrome.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
test/screenshotter/images/DisplayStyle-chrome.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
test/screenshotter/images/Exponents-chrome.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
test/screenshotter/images/FractionTest-chrome.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
test/screenshotter/images/Functions-chrome.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
test/screenshotter/images/GreekLetters-chrome.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
test/screenshotter/images/KaTeX-chrome.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
test/screenshotter/images/Lap-chrome.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
test/screenshotter/images/Lap_alt-firefox.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
test/screenshotter/images/LeftRight-chrome.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
test/screenshotter/images/LeftRightListStyling-chrome.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
test/screenshotter/images/LeftRightStyleSizing-chrome.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
test/screenshotter/images/NestedFractions-chrome.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
test/screenshotter/images/NullDelimiterInteraction-chrome.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
test/screenshotter/images/OpLimits-chrome.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
test/screenshotter/images/Overline-chrome.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
test/screenshotter/images/Phantom-chrome.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
test/screenshotter/images/PrimeSpacing-chrome.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
test/screenshotter/images/RlapBug-chrome.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
test/screenshotter/images/Rule-chrome.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
test/screenshotter/images/Sizing-chrome.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
test/screenshotter/images/SizingBaseline-chrome.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
test/screenshotter/images/Spacing-chrome.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
test/screenshotter/images/Sqrt-chrome.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
test/screenshotter/images/SqrtRoot-chrome.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
test/screenshotter/images/SupSubCharacterBox-chrome.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
test/screenshotter/images/SupSubHorizSpacing-chrome.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
test/screenshotter/images/SupSubOffsets-chrome.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
test/screenshotter/images/Text-chrome.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
test/screenshotter/images/VerticalSpacing-chrome.png
Normal file
After Width: | Height: | Size: 19 KiB |
|
@ -8,6 +8,9 @@
|
|||
#math, #pre, #post {
|
||||
font-size: 4em;
|
||||
}
|
||||
body {
|
||||
font-family: "DejaVu Serif",serif;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|