[docs] Port markdown to Docsy

This CL lands copies all the documentation in /site into /site2
but also adds frontmatter to each page.

Additionally it adds a Hugo `config.toml` file.

Once the new documentation server is live the original /site
directory will be removed and /site2 will be renamed /site.

Bugs: skia:11799
Change-Id: Ic300cf5c2a2a8fa2f9acc3455251bf818cb96a52
Docs-Preview: https://skia.org/?cl=386116
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/386116
Reviewed-by: Joe Gregorio <jcgregorio@google.com>
diff --git a/site2/docs/dev/_index.md b/site2/docs/dev/_index.md
new file mode 100644
index 0000000..0eccb14
--- /dev/null
+++ b/site2/docs/dev/_index.md
@@ -0,0 +1,11 @@
+---
+title: 'Developer Documentation'
+linkTitle: 'Developers'
+
+weight: 2
+menu:
+  main:
+    weight: 100
+---
+
+If you want to make changes to the Skia code, this is the place for you.
diff --git a/site2/docs/dev/chrome/_index.md b/site2/docs/dev/chrome/_index.md
new file mode 100644
index 0000000..6aa035a
--- /dev/null
+++ b/site2/docs/dev/chrome/_index.md
@@ -0,0 +1,43 @@
+
+---
+title: "Skia in Chrome"
+linkTitle: "Skia in Chrome"
+
+weight: 7
+
+---
+
+
+Changes to the Skia repository will be rolled into Chromium by the AutoRoll bot
+several times per day.
+
+If you have a Skia change that needs to be tested in Chrome, or which requires
+associated changes in that repository, see the guides in this section for tips
+on execution.
+
+For problems in Chromium related to Skia rolls:
+
+  * Go to https://autoroll.skia.org/r/skia-autoroll. Login with google.com
+    account and click the STOP button to pause new rolls.
+  * Revert the offending DEPS roll.
+  * If an obvious owner cannot be found in the list of CLs, assign to the Skia
+    Gardener, listed in the gardeners widget on https://status.skia.org and as
+    a reviewer on the roll CL.
+  * If the Skia Gardener cannot be assigned, cc them and assign the issue to hcm@.
+
+For more tips on bug triage and labeling, see the [Issue Tracker page](../../user/issue-tracker/).
+
+Branching for Chrome
+--------------------
+
+Every 6 weeks, we cut a new branch in Skia to reflect the new release branch in
+Chrome, eg. [refs/heads/chrome/m75](https://skia.googlesource.com/skia/+/chrome/m75).
+This process is simplified by running [tools/chrome_release_branch](https://skia.googlesource.com/skia/+/7a5b6ec0f6c01d3039e3ec30de6f8065ffc8aac4/tools/chrome_release_branch.py').
+This script handles creation of the branch itself, as well as associated
+housekeeping like updating the Chrome milestone number for the next release,
+setting up the [commit queue]('https://skia.googlesource.com/skia/+/infra/config/commit-queue.cfg')
+for the new branch. For example:
+
+    tools/chrome_release_branch <commit hash>
+
+
diff --git a/site2/docs/dev/chrome/blink.md b/site2/docs/dev/chrome/blink.md
new file mode 100644
index 0000000..3ad5dcf
--- /dev/null
+++ b/site2/docs/dev/chrome/blink.md
@@ -0,0 +1,93 @@
+
+---
+title: "Blink layout tests"
+linkTitle: "Blink layout tests"
+
+---
+
+
+How to land Skia changes that change Blink layout test results.
+
+Changes that affect a small number of layout test results
+---------------------------------------------------------
+Changes affecting fewer than ~20 layout tests can be rebaselined without
+special coordination with the Blink gardener using these steps:
+
+1. Prepare your Skia change, taking note of which layout tests will turn red
+   \(see http://www.chromium.org/developers/testing/webkit-layout-tests for more
+   detail on running the Blink layout tests\).
+2. Check in your code to the Skia repo.
+3. Ahead of the Skia auto roll including your change, manually push a change to the
+   Blink LayoutTests/TestExpectations [file](https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/web_tests/TestExpectations), flagging tests expected to fail as a result of your change as follows:
+   foo/bar/test-name.html [ Failure Pass ]  # Needs rebaseline
+
+4. Wait for the Skia roll to land successfully.
+5. Check in another change to the Blink TestExpectations file removing all the
+  skipped test expectations you add earlier, an run `git cl rebaseline` which will prompt the automatic rebaseline.
+
+
+
+Changes that affect a large number of test results
+--------------------------------------------------
+Where a 'large number' or 'many' means more than about 20.
+Follow the instructions below:
+
+In the following the term 'code suppression' means a build flag \(a\.k\.a\. define\).
+Such code suppressions should be given a name with the form SK\_IGNORE\_xxx\_FIX.
+
+Updating the version of Skia in Chromium is called a 'roll'.
+The Auto Roll Bot performs this roll multiple times per day, and can also be done manually.
+See https://chromium.googlesource.com/chromium/src/+log/master/DEPS and search for skia\-deps\-roller.
+
+### Setup
+#### Code suppression does not yet exist \- Direct method
+1. Make a change in Skia which will change many Blink layout tests.
+2. Put the change behind a code suppression.
+3. Check in the change to the Skia repository.
+4. Manually roll Skia or append the autoroll with the code suppression to
+   Chromium's 'skia/chromium\_skia\_defines\.gypi'
+
+#### Code suppression does not yet exist \- Alternate method
+1. Add code suppression to Chromium's 'skia/chromium\_skia\_defines\.gypi' before making code
+   changes in Skia.
+2. Make a change in Skia which will change many Blink layout tests.
+3. Put the change behind a code suppression.
+4. Check in the change to the Skia repository.
+5. Wait for Skia roll into Chromium.
+
+#### Code suppression exists in header
+1. Remove code suppression from header file in Chromium and add code suppression to
+   Chromium's 'skia/chromium\_skia\_defines\.gypi'.
+   The code suppression cannot be in a header file and a defined in a gyp file at the
+   same time or a multiple definition warning will be treated as an error and break
+   the Chromium build.
+
+### Rebaseline
+1. Choose a time when the Blink tree is likely to be quiet. Avoid PST afternoons in
+   particular. The bigger the change, the more important this is. Regardless,
+   determine who the Blink gardener is and notify them. You will be making the
+   Chromium\.WebKit tree very red for an extended period, and the gardener needs to
+   know that they are not expected to fix it.
+2. Create a CL removing the code suppression from Chromium's
+   skia/chromium\_skia\_defines\.gypi while simultaneously adding [ NeedsRebaseline ]
+   lines to Blink's LayoutTests/TestExpectations [file](https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/web_tests/TestExpectations).
+   Then the auto rebaseline bot will take care of the work of actually checking in the
+   new images. This is generally acceptable for up to 600 or so rebaselined images.
+   Above that you might still use [ NeedsRebaseline ], but it's best to coordinate with
+   the gardener. This should go through the CQ cleanly.
+3. Be careful with tests that are already failing or flakey. These may or may not need
+   to be rebaselined and flakey tests should not be removed from TestExpectations
+   regardless. In such cases revert the TestExpectations changes before committing.
+4. If you are not the one handling the cleanup step, please open a Skia Issue of the
+   form
+   Title: "Remove code suppression SK\_IGNORE\_xxx\_FIX\."
+   Comment: "Code suppression SK\_IGNORE\_xxx\_FIX rebaselined with Blink revision
+   123456\." and assign it to the individual responsible for the cleanup step.
+
+### Cleanup
+1. Remove the now unused old code from Skia and any defines which were introduced
+   to suppress the new code.
+2. Check in the cleanup change to the Skia repository.
+3. Wait for Skia roll into Chromium.
+
+
diff --git a/site2/docs/dev/chrome/changes.md b/site2/docs/dev/chrome/changes.md
new file mode 100644
index 0000000..1a1a5f2
--- /dev/null
+++ b/site2/docs/dev/chrome/changes.md
@@ -0,0 +1,41 @@
+
+---
+title: "Chrome changes"
+linkTitle: "Chrome changes"
+
+---
+
+
+If your change modifies the Skia API, you may also need to land a change in Chromium.
+
+The strategy you use to synchronize changes in the Skia and Chromium
+repositories may differ based on the nature of the change, but in general, we
+recommend using build flag suppressions \(defines\)\.
+We also prefer making the old code path opt-in where possible.
+
+Method 1 \(preferred\) \- Make the old code path opt\-in for Chromium
+
+  * Add new code to Skia, leaving the old code in place.
+  * Deprecate the old code path so that it must be enabled with a flag such as
+    'SK_SUPPORT_LEGACY_XXX'.
+  * Synchronize the above changes in Skia with a Chromium commit to
+    'skia/skia_common.gypi' or 'skia/config/SkUserConfig.h' to enable the
+    deprecated Skia API.
+      * Note that the code suppression cannot exist in both the header file and
+      the gyp file, it should only reside in one location.
+  * Test the new or updated Skia API within Chromium.
+  * Remove the flag and code when the legacy code path is no longer in use.
+
+Method 2 \- Make the new code path opt\-in for Chromium
+
+  * Add new code to Skia, suppressed by a flag.
+  * Leave the old code path in place.
+  * Set the flag in Chromium's 'skia/skia_common.gypi' or
+    'skia/config/SkUserConfig.h' to enable the new or updated Skia API.
+  * Test the new or updated Skia API within Chromium.
+  * Remove the code suppression \(and code\) when the legacy API is no longer
+    in use.
+
+If your changes will affect Blink layout tests, see detailed instructions about
+how to synchronize the changes between Skia, Blink, and Chromium [here](./blink).
+
diff --git a/site2/docs/dev/chrome/commandbuffer.md b/site2/docs/dev/chrome/commandbuffer.md
new file mode 100644
index 0000000..20c55ef
--- /dev/null
+++ b/site2/docs/dev/chrome/commandbuffer.md
@@ -0,0 +1,28 @@
+
+---
+title: "Chromium Command Buffer"
+linkTitle: "Chromium Command Buffer"
+
+---
+
+
+It is possible to run Skia's correctness tool, dm, and benchmarking tool,
+nanobench, on top of the GL ES interface provided by Chromium's command
+buffer.
+
+The Skia tools are always built with this support. They dynamically load
+the command buffer as a shared library and thus no GYP/GN flags are
+required.
+
+The command buffer standalone shared library is built in a Chromium checkout
+by building the `command_buffer_gles2` target. The command buffer should be
+built with the `is_component_build` in GN set to false. This will produce a .so,
+.dylib, or .dll depending on the target OS. This should be copied alongside
+the dm or nanobench executable built from a Skia repository.
+
+Both tools have a `commandbuffer` config which can be used with the `--config`
+option to the tool and will run the tests or benchmarks using the command buffer
+library. Unit tests in dm always run on all appropriate and available backends
+regardless of the `--config` flag.
+
+
diff --git a/site2/docs/dev/chrome/multi_repo_trybots.md b/site2/docs/dev/chrome/multi_repo_trybots.md
new file mode 100644
index 0000000..68d503b
--- /dev/null
+++ b/site2/docs/dev/chrome/multi_repo_trybots.md
@@ -0,0 +1,91 @@
+
+---
+title: "Multiple repo Chromium trybots"
+linkTitle: "Multiple repo Chromium trybots"
+
+---
+
+
+When a proposed Skia change will require a change in Chromium or Blink it is
+often helpful to locally create the Chromium and Blink changes and test with the
+proposed Skia change. This often happens with Skia API changes and changes
+which affect Blink layout tests. While simple to do locally, this explains how
+to do so on the Chromium trybots.
+
+Skia only changes
+-----------------
+If the Skia patch is already in Gerrit and there are no associated Chromium
+changes, then it is possible to just run the Chromium trybots. This will apply
+the Skia patch and run the bot.
+
+Skia and Chromium changes
+-------------------------
+If the Skia patch is already in Gerrit and there are associated Chromium
+changes, then in the Chromium CL add the following to
+\<chromium>/src/DEPS in the 'hooks' array.
+
+      {
+        'name': 'fetch_custom_patch',
+        'pattern': '.',
+        'action': [ 'git', '-C', 'src/third_party/skia/',
+                    'fetch', 'https://skia.googlesource.com/skia', 'refs/changes/13/10513/13',
+        ],
+      },
+      {
+        'name': 'apply_custom_patch',
+        'pattern': '.',
+        'action': ['git', '-C', 'src/third_party/skia/',
+                   '-c', 'user.name=Custom Patch', '-c', 'user.email=custompatch@example.com',
+                   'cherry-pick', 'FETCH_HEAD',
+        ],
+      },
+
+Modify the 'refs/changes/XX/YYYY/ZZ' to the appropriate values (where YYYY is
+the numeric change number, ZZ is the patch set number and XX is the last two
+digits of the numeric change number). This can be seen in the 'Download' link on
+Gerrit.
+
+If this is for a project other than Skia, update the checkout directory and
+fetch source. Note that this can be used multiple times to apply multiple
+issues.
+
+An example of this being used can be seen at
+https://crrev.com/2786433004/#ps1 .
+
+To test locally, run `gclient runhooks` to update the Skia source code.
+Note that if your local skia patch in `third_party/skia` isn't clean (e.g., you
+already applied some patch to it), then `gclient runhooks` won't successfully
+run. In that case, run `git reset --hard` inside `third_party/skia` before
+`gclient runhooks`.
+
+Arbitrary changes
+-----------------
+If the patch is to files where the above is not possible, then it is still
+possible to patch the files manually by adding the following to
+\<chromium>/src/DEPS in the 'hooks' array just before the 'gyp' hook.
+
+      {
+        'name': 'apply_custom_patch',
+        'pattern': '.',
+        'action': ['python2',
+                   '-c', 'from distutils.dir_util import copy_tree; copy_tree("src/patch/", "src/");'
+        ],
+      },
+
+Then, copy all 'out of tree' files into \<chromium>/src/patch/, using the same
+directory structure used by Chromium. When `gclient runhooks` is run, the files
+in \<chromium>/src/patch/ will be copied to and overwrite corresponding files in
+\<chromium>/src/. For example, if changing \<skia>/include/core/SkPath.h, place
+a copy of the modified SkPath.h at
+\<chromium>/src/patch/third_party/skia/include/core/SkPath.h.
+
+An example of this being used can be seen at
+https://crrev.com/1866773002/#ps20001 .
+
+
+Try the patch
+-------------
+After committing a \<chromium>/src/DEPS or \<chromium>/src/patch/ change
+locally, `git cl upload` can be used in the usual way. Be sure to add
+`COMMIT=false` to the issue description to avoid accidentally checking it in.
+
diff --git a/site2/docs/dev/chrome/repo.md b/site2/docs/dev/chrome/repo.md
new file mode 100644
index 0000000..46f197c
--- /dev/null
+++ b/site2/docs/dev/chrome/repo.md
@@ -0,0 +1,23 @@
+
+---
+title: "Working in a Chromium repo"
+linkTitle: "Working in a Chromium repo"
+
+---
+
+
+To work on Skia inside a Chromium checkout, run the following:
+
+    cd chromium/src/third_party/skia
+    python2 tools/git-sync-deps
+    bin/gn gen out/Debug
+
+The second command does a minimal "just sync the DEPS" emulation of `gclient
+sync` for Skia into chromium/src/third_party/skia/third_party.  After that,
+`ninja -C out/Debug dm` in chromium/src/third_party/skia will get you rolling.
+
+We no longer recommend the .gclient file manipulation to have Chromium DEPS also
+sync Skia's DEPS.  Most of those DEPS are for building and testing only;
+Chromium doesn't need any of them, and it can be confusing and problematic if
+they somehow get mixed into the Chromium build.
+
diff --git a/site2/docs/dev/contrib/_index.md b/site2/docs/dev/contrib/_index.md
new file mode 100644
index 0000000..e873dcc
--- /dev/null
+++ b/site2/docs/dev/contrib/_index.md
@@ -0,0 +1,67 @@
+---
+title: 'Contributing to Skia'
+linkTitle: 'Contributing'
+
+weight: 1
+menu:
+  main:
+    weight: 40
+---
+
+Here some ways you can get involved and help us improve Skia.
+
+## Report Bugs
+
+Find bugs to fix or report new bugs in the
+[Skia issue tracker](http://bug.skia.org/). You can also search the
+[Chromium issue tracker](http://code.google.com/p/chromium/issues/list) for bugs
+related to graphics or Skia.
+
+## Test
+
+Write an application or tool that will exercise the Skia code differently than
+our current set of tests and verify that Skia works as expected. Draw something
+interesting and profile it to find ways to speed up Skia's implementation.We
+cannot always fix issues or support every scenario, but we welcome any bugs
+found so we can assess and prioritize them. (If you find _and_ fix a bug, even
+better!)
+
+## Contribute Code
+
+Whether you develop a new feature or a fix for an existing bug in the Skia code
+base, you will need a committer to review and approve the change. There are some
+steps that can speed up the review process:
+
+- Keep your code submissions small and targeted.
+- When possible, have a fellow contributor review your change in advance of
+  submission.
+- Propose new features to the project leads by opening a feature bug or posting
+  to skia-discuss ahead of development.
+
+For more information, see [How to submit a patch](/dev/contrib/submit).
+
+For background on the project and an outline of the types of roles interested
+parties can take on, see [Project Roles](/roles).
+
+Anyone contributing code to Skia must sign a Contributor License Agreement and
+ensure they are listed in the AUTHORS file:
+
+- Individual contributors can complete the
+  [Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual)
+  online.
+- If you are contributing on behalf of a corporation, fill out the
+  [Corporate Contributor License Agreement](https://developers.google.com/open-source/cla/corporate)
+  and send it in as described on that page.
+
+- If it is your first time submitting code or you have not previously done so,
+  add your (or your organization's) name and contact info to the
+  [AUTHORS file](https://skia.googlesource.com/skia/+/master/AUTHORS) as a part
+  of your CL.
+
+REVIEWERS: Before you LGTM a change, verify that the contributor is listed in
+the AUTHORS file.
+
+If they are not, a Googler must ensure that the individual or their corporation
+has signed the CLA by searching
+[go/cla-signers](https://goto.google.com/cla-signers). Then have an entry added
+to the AUTHORS file with the CL.
diff --git a/site2/docs/dev/contrib/bazel.md b/site2/docs/dev/contrib/bazel.md
new file mode 100644
index 0000000..5a40e1b
--- /dev/null
+++ b/site2/docs/dev/contrib/bazel.md
@@ -0,0 +1,102 @@
+
+---
+title: "Notes about Bazel Builds"
+linkTitle: "Notes about Bazel Builds"
+
+---
+
+
+Skia cannot be built with Bazel yet.
+
+But you should be able to build and run the trivial `tools/bazel_test.cc`:
+
+    $ bazel test ...
+
+Dependencies
+------------
+
+`WORKSPACE.bazel` acts like `DEPS`, listing external dependencies and how to
+fetch them.  You can call `bazel sync`, or just let `bazel {build,test,run}`
+handle it as needed on its own.  The easiest way to add a new dependency is to
+start using `tag="..."` or `branch="..."` and then follow the advice of Bazel
+to pin that to the `commit` and `shallow_since` it suggests.
+
+We must provide Bazel build configuration for dependencies like `libpng` that
+don't provide their own.  For `libpng` that's `bazel/libpng.bazel`, linked by
+the `new_git_repository()` `build_file` argument, written relative to that
+fetched Git repo's root.  Its resemblance to `third_party/libpng/BUILD.gn` is
+no coincidence... it's pretty much a 1:1 translation between GN and Bazel.
+
+Everything that's checked in builds external dependencies from source.  I've
+not written an integrated system for substituting prebuilt versions of these
+dependencies (e.g. `/usr/include/png.h` and `/usr/lib/libpng.so`), instead
+leaving that up to users who want it.  The process is not exactly trivial, but
+closer to tedious than difficult.  Here's an example, overriding `libpng` to
+point to prebuilts from Homebrew in ~/brew:
+
+Each overridden dependency will need its own directory with a few files.
+
+    $ find overrides
+    overrides
+    overrides/libpng
+    overrides/libpng/include
+    overrides/libpng/WORKSPACE.bazel
+    overrides/libpng/BUILD.bazel
+
+`WORKSPACE.bazel` must be present, but in this case can be empty.
+
+    $ cat overrides/libpng/WORKSPACE.bazel
+
+`BUILD.bazel` is where it all happens:
+
+    $ cat overrides/libpng/BUILD.bazel
+    cc_library(
+        name = "libpng",
+        hdrs = ["include/png.h"],
+        srcs = ["include/pngconf.h", "include/pnglibconf.h"],
+        includes = ["include"],
+        linkopts = ["-lpng", "-L/Users/mtklein/brew/lib"],
+        visibility = ["//visibility:public"],
+    )
+
+`include` is a symlink I've made to `~/brew/include` because Bazel doesn't like
+absolute paths in `hdrs` or `includes`.  On the other hand, a symlink to
+`~/brew/lib` doesn't work here, though `-L/Users/mtklein/brew/lib` works fine.
+
+    $ readlink overrides/libpng/include
+    /Users/mtklein/brew/include/
+
+Finally, we point Bazel at all that using `--override_repository`:
+
+    $ bazel test ... --override_repository libpng=/Users/mtklein/overrides/libpng
+
+I expect building from source to be the most common use case, and it's more or
+less enough to simply know that we can substitute prebuilts this way.  The most
+interesting part to me is that we don't need to provide this mechanism... it's
+all there in stock Bazel.  This plan may all want some rethinking in the future
+if we want to add the option to trim the dependency entirely and make this
+tristate (build it, use it prebuilt, or trim).
+
+.bazelrc
+--------
+
+I have not (yet?) checked in a .bazelrc to the Skia repo, but have found it
+handy to write my own in ~/.bazelrc:
+
+    $ cat ~/.bazelrc
+    # Print more information on failures.
+    build --verbose_failures
+    test --test_output errors
+
+    # Create an ASAN config, try `bazel test --config asan ...`.
+    build:asan --copt -fsanitize=address
+    build:asan --copt -Wno-macro-redefined   # (_FORTIFY_SOURCE redefined.)
+    build:asan --linkopt -fsanitize=address
+
+    # Flip on and off prebuilt overrides easily.
+    build --override_repository libpng=/Users/mtklein/overrides/libpng
+
+I'm impressed by how much you can configure via bazelrc, and I think this
+should let our Bazel build configuration stay mostly focused on the structure
+of the project, less cluttered by build settings.
+
diff --git a/site2/docs/dev/contrib/cqkeywords.md b/site2/docs/dev/contrib/cqkeywords.md
new file mode 100644
index 0000000..74c6fbf
--- /dev/null
+++ b/site2/docs/dev/contrib/cqkeywords.md
@@ -0,0 +1,99 @@
+
+---
+title: "Commit Queue Keywords"
+linkTitle: "Commit Queue Keywords"
+
+---
+
+
+See [CQ
+documentation](https://chromium.googlesource.com/chromium/src/+/master/docs/infra/cq.md)
+for more information.
+
+Options in the form "Key: Value"  must appear in the last paragraph of the
+commit message to be used.
+
+
+Commit
+------
+
+If you are working on experimental code and do not want to risk accidentally
+submitting the change via the CQ, then you can mark it with "Commit: false".
+The CQ will immediately abandon the change if it contains this option.
+To do a dry run through the CQ please use Gerrit's [CQ Dry
+Run](https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/G5-X0_tfmok)
+feature.
+
+    Commit: false
+
+The CQ will run through its list of verifiers (reviewer check, trybots, tree check,
+presubmit check), and will close the issue instead of committing it.
+
+
+No-Dependency-Checks
+--------------------
+
+    No-Dependency-Checks: true
+
+The CQ rejects patchsets with open dependencies. An open dependency exists when a CL
+depends on another CL that is not yet closed. You can skip this check with this keyword.
+
+
+Cq-Include-Trybots
+------------------
+
+Allows you to add arbitrary trybots to the CQ's list of default trybots.
+The CQ will block till these tryjobs pass just like the default list of tryjobs.
+
+This is the format of the values of this keyword:
+
+    Cq-Include-Trybots: bucket1:bot1,bot2;bucket2:bot3,bot4
+
+Multiple lines are allowed:
+
+    Cq-Include-Trybots: bucket1:bot1
+    Cq-Include-Trybots: bucket1:bot2
+    Cq-Include-Trybots: bucket2:bot3
+    Cq-Include-Trybots: bucket2:bot4
+
+Here are some real world examples:
+
+    Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_asan_rel_ng
+    Cq-Include-Trybots: skia.primary:Test-Win10-Clang-ShuttleC-GPU-GTX960-x86_64-Debug-All-ANGLE
+    Cq-Include-Trybots: luci.skia.skia.primary:Build-Debian9-Clang-x86-devrel-Android_SKQP
+
+    FIXME: what bucket are skia bots in now?
+
+
+No-Tree-Checks
+--------------
+
+If you want to skip the tree status checks, to make the CQ commit a CL even if
+the tree is closed, you can add the following line to the CL description:
+
+    No-Tree-Checks: true
+
+This is discouraged, since the tree is closed for a reason. However, in rare
+cases this is acceptable, primarily to fix build breakages (i.e., your CL will
+help in reopening the tree).
+
+
+No-Presubmit
+------------
+
+If you want to skip the presubmit checks, add the following line to the CL description:
+
+    No-Presubmit: true
+
+
+No-Try
+------
+
+If you cannot wait for the try job results, you can add the following line to
+the CL description:
+
+    No-Try: true
+
+The CQ will then not run any try jobs for your change and will commit the CL as
+soon as the tree is open, assuming the presubmit check passes.
+
diff --git a/site2/docs/dev/contrib/directory.md b/site2/docs/dev/contrib/directory.md
new file mode 100644
index 0000000..418a200
--- /dev/null
+++ b/site2/docs/dev/contrib/directory.md
@@ -0,0 +1,48 @@
+
+---
+title: "The Skia Directory"
+linkTitle: "The Skia Directory"
+
+---
+
+
+*   Docs & Bugs
+    -   [Skia.org](https://skia.org/)
+    -   [Issue Tracker](https://bug.skia.org/)
+    -   [Autogenerated API Documentation](https://api.skia.org)
+
+*   Code Repositories
+    -   [Git repository](https://skia.googlesource.com/skia/)
+    -   [Other Skia project repositories](https://skia.googlesource.com/)
+    -   [GitHub Mirror](https://github.com/google/skia)
+    -   [Code Search](https://cs.skia.org) based on the version of Skia in the
+        Chromium tree.
+
+*   BuildBot Consoles
+    -   [Commit Status](https://status.skia.org/)
+    -   [Tree Status](https://tree-status.skia.org/) (requires login)
+    -   [BuildBot Console](https://build.chromium.org/p/client.skia/console)
+    -   [FYI BuildBot
+        Console](https://build.chromium.org/p/client.skia.fyi/console)
+    -   [Android BuildBot
+        Console](https://build.chromium.org/p/client.skia.android/console)
+    -   [Compile BuildBot
+        Console](https://build.chromium.org/p/client.skia.compile/console)
+
+*   Other
+    -   [Fiddle](https://fiddle.skia.org/) Try out Skia on the web!
+    -   [Gold](https://gold.skia.org/) Correctness testing.
+    -   [Perf](https://perf.skia.org/) Performance testing.
+    -   [Mon](https://mon.skia.org/) Grafana dashboard (requires login).
+    -   [Alerts](https://alerts.skia.org/) Monitor testing and bot status.
+    -   [BugChomper] (https://bugchomper.skia.org/) Prioritize bugs quickly.
+    -   [Code Review](https://skia-review.googlesource.com/)
+
+*   Mailing Lists
+    -   [Discussion Mailing List](https://groups.google.com/group/skia-discuss)
+    -   [Code Review Announce
+        List](https://groups.google.com/a/skia.org/forum/#!forum/reviews)
+    -   [Bug Announce
+        List](https://groups.google.com/a/skia.org/forum/#!forum/bugs)
+
+
diff --git a/site2/docs/dev/contrib/patch.md b/site2/docs/dev/contrib/patch.md
new file mode 100644
index 0000000..1205e66
--- /dev/null
+++ b/site2/docs/dev/contrib/patch.md
@@ -0,0 +1,74 @@
+---
+title: 'Applying patches'
+linkTitle: 'Applying patches'
+---
+
+If you are a Skia committer and have been asked to commit an
+externally-submitted patch, this is how to do it. (This technique is useful in
+other situations too, like if you just want to try out somebody else's patch
+locally.)
+
+Notes:
+
+- For the examples below, we will assume that this is the change you want to
+  patch into your local checkout: https://codereview.appspot.com/6201055/
+- These instructions should work on Mac or Linux; Windows is trickier, because
+  there is no standard Windows "patch" tool.
+
+See also [Contributing Code for The Chromium Projects]
+(http://dev.chromium.org/developers/contributing-code#TOC-Instructions-for-Reviewer:-Checking-in-the-patch-for-a-non-committer).
+
+If you use `git cl`, then you should be able to use the shortcut:
+
+```
+git cl patch 6201055
+```
+
+If you use `gcl`, or the above doesn't work, the following should always work.
+
+1. Prepare your local workspace to accept the patch.
+
+   - cd into the root directory (usually `trunk/`) of the workspace where you
+     want to apply the patch.
+   - Make sure that the workspace is up-to-date and clean (or "updated and clean
+     enough" for your purposes). If the codereview patch was against an old
+     revision of the repo, you may need to sync your local workspace to that
+     same revision.
+
+2. Download the raw patch set.
+
+   - Open the codereview web page and look for the "Download raw patch set" link
+     near the upper right-hand corner. Right-click on that link and copy it to
+     the clipboard. (In my case, the link is
+     https://codereview.appspot.com/download/issue6201055_1.diff )
+   - If you are on Linux or Mac and have "curl" or "wget" installed, you can
+     download the patch from the command line:
+
+   ```
+   curl https://codereview.appspot.com/download/issue6201055_1.diff
+   --output patch.txt
+   # or...
+   wget https://codereview.appspot.com/download/issue6201055_1.diff
+   --output-document=patch.txt
+   ```
+
+   - Otherwise, figure out some other way to download this file and save it as
+     `patch.txt`
+
+3. Apply this patch to your local checkout.
+
+   - You should still be in the root directory of the workspace where you want
+     to apply the patch.
+
+   ```
+   patch -p1 <patch.txt
+   ```
+
+   - Then you can run `diff` and visually check the local changes.
+
+4. Complications: If the patch fails to apply, the following may be happening:
+
+   - Wrong revision. Maybe your local workspace is not up to date? Or maybe the
+     patch was made against an old revision of the repository, and cannot be
+     applied to the latest revision? (In that case, revert any changes and sync
+     your workspace to an older revision, then re-apply the patch.)
diff --git a/site2/docs/dev/contrib/revert.md b/site2/docs/dev/contrib/revert.md
new file mode 100644
index 0000000..b8e7a2e
--- /dev/null
+++ b/site2/docs/dev/contrib/revert.md
@@ -0,0 +1,45 @@
+
+---
+title: "How to revert a CL"
+linkTitle: "How to revert a CL"
+
+---
+
+
+Using one-click revert
+----------------------
+*   Find the codereview issue for the CL you want to revert.
+*   Click the "revert" button.
+
+Using Git
+---------
+
+Update the local repository
+
+    git fetch origin master
+
+Create a local branch with origin/master as its start point.
+
+    git checkout -b revert$RANDOM origin/master
+
+Find the SHA1 of the commit you want to revert
+
+    git log origin/master
+
+Create a revert commit.
+
+    git revert <SHA1>
+
+Upload it to Gerrit.
+
+    git cl upload
+
+Land the revert in origin/master.
+
+    git cl land
+
+Delete the local revert branch.
+
+    git checkout --detach && git branch -D @{-1}
+
+
diff --git a/site2/docs/dev/contrib/style.md b/site2/docs/dev/contrib/style.md
new file mode 100644
index 0000000..5759b78
--- /dev/null
+++ b/site2/docs/dev/contrib/style.md
@@ -0,0 +1,529 @@
+---
+title: 'Coding Style Guidelines'
+linkTitle: 'Coding Style Guidelines'
+---
+
+These conventions have evolved over time. Some of the earlier code in both
+projects doesn't strictly adhere to the guidelines. However, as the code evolves
+we hope to make the existing code conform to the guildelines.
+
+## Files
+
+We use .cpp and .h as extensions for c++ source and header files.
+
+Headers that aren't meant for public consumption should be placed in src
+directories so that they aren't in a client's search path, or in
+include/private if they need to be used by public headers.
+
+We prefer to minimize includes. If forward declaring a name in a header is
+sufficient then that is preferred to an include.
+
+Forward declarations and file includes should be in alphabetical order.
+
+<span id="no-define-before-sktypes"></span>
+Do not use #if/#ifdef before including "SkTypes.h" (directly or indirectly).
+Most things you'd #if on tend to not yet be decided until SkTypes.h.
+
+We use 4 spaces, not tabs.
+
+We use Unix style endlines (LF).
+
+We prefer no trailing whitespace but aren't very strict about it.
+
+We wrap lines at 100 columns unless it is excessively ugly (use your judgement).
+
+## Naming
+
+Most externally visible types and functions use an Sk- prefix to designate
+they're part of Skia, but code in Ganesh uses Gr-. Nested types need not be
+prefixed.
+
+<!--?prettify?-->
+
+```
+class SkClass {
+public:
+    class HelperClass {
+        ...
+    };
+};
+```
+
+Data fields in structs, classes, and unions that have methods begin with
+lower-case f and are then camel-capped, to distinguish those fields from other
+variables. Types that are predominantly meant for direct field access don't
+need f-decoration.
+
+<!--?prettify?-->
+
+```
+struct GrCar {
+    float milesDriven;
+    Color color;
+};
+
+class GrMotorcyle {
+public:
+    float getMilesDriven() const { return fMilesDriven; }
+    void  setMilesDriven(float milesDriven) { fMilesDriven = milesDriven; }
+
+    Color getColor() const { return fColor; }
+private:
+    float fMilesDriven;
+    Color fColor;
+};
+```
+
+Global variables are similar but prefixed with g and camel-capped.
+
+<!--?prettify?-->
+
+```
+bool gLoggingEnabled;
+```
+
+Local variables and arguments are camel-capped with no initial cap.
+
+<!--?prettify?-->
+
+```
+int herdCats(const Array& cats) {
+    int numCats = cats.count();
+}
+```
+
+Variables declared `constexpr` or `const`, and whose value is fixed for the
+duration of the program, are named with a leading "k" and then camel-capped.
+
+<!--?prettify?-->
+
+```
+int drawPicture() {
+    constexpr SkISize kPictureSize = {100, 100};
+    constexpr float kZoom = 1.0f;
+}
+```
+
+Enum values are also prefixed with k. Unscoped enum values are postfixed with
+an underscore and singular name of the enum name. The enum itself should be
+singular for exclusive values or plural for a bitfield. If a count is needed it
+is `k<singular enum name>Count` and not be a member of the enum (see example),
+or a kLast member of the enum is fine too.
+
+<!--?prettify?-->
+
+```
+// Enum class does not need suffixes.
+enum class SkPancakeType {
+     kBlueberry,
+     kPlain,
+     kChocolateChip,
+};
+```
+
+<!--?prettify?-->
+
+```
+// Enum should have a suffix after the enum name.
+enum SkDonutType {
+     kGlazed_DonutType,
+     kSprinkles_DonutType,
+     kChocolate_DonutType,
+     kMaple_DonutType,
+
+     kLast_DonutType = kMaple_DonutType
+};
+
+static const SkDonutType kDonutTypeCount = kLast_DonutType + 1;
+```
+
+<!--?prettify?-->
+
+```
+enum SkSausageIngredientBits {
+    kFennel_SausageIngredientBit = 0x1,
+    kBeef_SausageIngredientBit   = 0x2
+};
+```
+
+<!--?prettify?-->
+
+```
+enum SkMatrixFlags {
+    kTranslate_MatrixFlag = 0x1,
+    kRotate_MatrixFlag    = 0x2
+};
+```
+
+Macros are all caps with underscores between words. Macros that have greater
+than file scope should be prefixed SK or GR.
+
+Static non-class functions in implementation files are lower-case with
+underscores separating words:
+
+<!--?prettify?-->
+
+```
+static inline bool tastes_like_chicken(Food food) {
+    return kIceCream_Food != food;
+}
+```
+
+Externed functions or static class functions are camel-capped with an initial cap:
+
+<!--?prettify?-->
+
+```
+bool SkIsOdd(int n);
+
+class SkFoo {
+public:
+    static int FooInstanceCount();
+
+    // Not static.
+    int barBaz();
+};
+```
+
+## Macros
+
+Ganesh macros that are GL-specific should be prefixed GR_GL.
+
+<!--?prettify?-->
+
+```
+#define GR_GL_TEXTURE0 0xdeadbeef
+```
+
+Ganesh prefers that macros are always defined and the use of `#if MACRO` rather than
+`#ifdef MACRO`.
+
+<!--?prettify?-->
+
+```
+#define GR_GO_SLOWER 0
+...
+#if GR_GO_SLOWER
+    Sleep(1000);
+#endif
+```
+
+The rest of Skia tends to use `#ifdef SK_MACRO` for boolean flags.
+
+## Braces
+
+Open braces don't get a newline. `else` and `else if` appear on same line as
+opening and closing braces unless preprocessor conditional compilation
+interferes. Braces are always used with `if`, `else`, `while`, `for`, and `do`.
+
+<!--?prettify?-->
+
+```
+if (...) {
+    oneOrManyLines;
+}
+
+if (...) {
+    oneOrManyLines;
+} else if (...) {
+    oneOrManyLines;
+} else {
+    oneOrManyLines;
+}
+
+for (...) {
+    oneOrManyLines;
+}
+
+while (...) {
+    oneOrManyLines;
+}
+
+void function(...) {
+    oneOrManyLines;
+}
+
+if (!error) {
+    proceed_as_usual();
+}
+#if HANDLE_ERROR
+else {
+    freak_out();
+}
+#endif
+```
+
+## Flow Control
+
+There is a space between flow control words and parentheses, and between
+parentheses and braces:
+
+<!--?prettify?-->
+
+```
+while (...) {
+}
+
+do {
+} while (...);
+
+switch (...) {
+...
+}
+```
+
+Cases and default in switch statements are indented from the switch.
+
+<!--?prettify?-->
+
+```
+switch (color) {
+    case kBlue:
+        ...
+        break;
+    case kGreen:
+        ...
+        break;
+    ...
+    default:
+       ...
+       break;
+}
+```
+
+Fallthrough from one case to the next is annotated with `[[fallthrough]]`.
+However, when multiple case statements in a row are used, they do not need the
+`[[fallthrough]]` annotation.
+
+<!--?prettify?-->
+
+```
+switch (recipe) {
+    ...
+    case kSmallCheesePizza_Recipe:
+    case kLargeCheesePizza_Recipe:
+        ingredients |= kCheese_Ingredient | kDough_Ingredient | kSauce_Ingredient;
+        break;
+    case kCheeseOmelette_Recipe:
+        ingredients |= kCheese_Ingredient;
+        [[fallthrough]]
+    case kPlainOmelette_Recipe:
+        ingredients |= (kEgg_Ingredient | kMilk_Ingredient);
+        break;
+    ...
+}
+```
+
+When a block is needed to declare variables within a case follow this pattern:
+
+<!--?prettify?-->
+
+```
+switch (filter) {
+    ...
+    case kGaussian_Filter: {
+        Bitmap srcCopy = src->makeCopy();
+        ...
+    } break;
+    ...
+};
+```
+
+## Classes
+
+Unless there is a need for forward declaring something, class declarations
+should be ordered `public`, `protected`, `private`. Each should be preceded by a
+newline. Within each visibility section (`public`, `private`), fields should not be
+intermixed with methods. It's nice to keep all data fields together at the end.
+
+<!--?prettify?-->
+
+```
+class SkFoo {
+
+public:
+    ...
+
+protected:
+    ...
+
+private:
+    void barHelper(...);
+    ...
+
+    SkBar fBar;
+    ...
+};
+```
+
+Virtual functions that are overridden in derived classes should use override,
+and the virtual keyword should be omitted.
+
+<!--?prettify?-->
+
+```
+void myVirtual() override {
+}
+```
+
+If you call a method on a parent type that must stand out as specifically the
+parent's version of that method, we usually privately alias that parent type to
+`INHERITED` within the class. That lets calls like `INHERITED::onFoo()` stand
+out visually. No need for `this->` when using `INHERITED::`.
+
+<!--?prettify?-->
+
+```
+class GrDillPickle : public GrPickle {
+    ...
+    bool onTasty() const override {
+        return INHERITED::onTasty()
+            && fFreshDill;
+    }
+    ...
+private:
+    bool fFreshDill;
+    using INHERITED = GrPickle;
+};
+```
+
+Constructor initializers should be one per line, indented, with punctuation
+placed before the initializer.
+
+<!--?prettify?-->
+
+```
+GrDillPickle::GrDillPickle()
+    : GrPickle()
+    , fSize(kDefaultPickleSize) {
+    ...
+}
+```
+
+Constructors that take one argument should almost always be explicit, with
+exceptions made only for the (rare) automatic compatibility class.
+
+<!--?prettify?-->
+
+```
+class Foo {
+    explicit Foo(int x);  // Good.
+    Foo(float y);         // Spooky implicit conversion from float to Foo.  No no no!
+    ...
+};
+```
+
+Method calls within method calls should be prefixed with dereference of the
+'this' pointer. For example:
+
+<!--?prettify?-->
+
+```
+this->method();
+```
+
+A common pattern for virtual methods in Skia is to include a public non-virtual
+(or final) method, paired with a private virtual method named "onMethodName".
+This ensures that the base-class method is always invoked and gives it control
+over how the virtual method is used, rather than relying on each subclass to
+call `INHERITED::onMethodName`. For example:
+
+<!--?prettify?-->
+
+```
+class SkSandwich {
+public:
+    void assemble() {
+        // All sandwiches must have bread on the top and bottom.
+        this->addIngredient(kBread_Ingredient);
+        this->onAssemble();
+        this->addIngredient(kBread_Ingredient);
+    }
+    bool cook() {
+        return this->onCook();
+    }
+
+private:
+    // All sandwiches must implement onAssemble.
+    virtual void onAssemble() = 0;
+    // Sandwiches can remain uncooked by default.
+    virtual bool onCook() { return true; }
+};
+
+class SkGrilledCheese : public SkSandwich {
+private:
+    void onAssemble() override {
+        this->addIngredient(kCheese_Ingredient);
+    }
+    bool onCook() override {
+        return this->toastOnGriddle();
+    }
+};
+
+class SkPeanutButterAndJelly : public SkSandwich {
+private:
+    void onAssemble() override {
+        this->addIngredient(kPeanutButter_Ingredient);
+        this->addIngredient(kGrapeJelly_Ingredient);
+    }
+};
+```
+
+## Integer Types
+
+We follow the Google C++ guide for ints and are slowly making older code conform to this
+
+(http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Integer_Types)
+
+Summary: Use `int` unless you have need a guarantee on the bit count, then use
+`stdint.h` types (`int32_t`, etc). Assert that counts, etc are not negative instead
+of using unsigned. Bitfields use `uint32_t` unless they have to be made shorter
+for packing or performance reasons.
+
+## Function Parameters
+
+Mandatory constant object parameters are passed to functions as const references.
+Optional constant object parameters are passed to functions as const pointers.
+Mutable object parameters are passed to functions as pointers.
+We very rarely pass anything by non-const reference.
+
+<!--?prettify?-->
+
+```
+// src and paint are optional
+void SkCanvas::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
+                              const SkRect& dst, const SkPaint* paint = nullptr);
+
+// metrics is mutable (it is changed by the method)
+SkScalar SkPaint::getFontMetrics(FontMetric* metrics, SkScalar scale) const;
+
+```
+
+If function arguments or parameters do not all fit on one line, the overflowing
+parameters may be lined up with the first parameter on the next line
+
+<!--?prettify?-->
+
+```
+void drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst,
+                    const SkPaint* paint = nullptr) {
+    this->drawBitmapRectToRect(bitmap, nullptr, dst, paint,
+                               kNone_DrawBitmapRectFlag);
+}
+```
+
+or all parameters placed on the next line and indented eight spaces
+
+<!--?prettify?-->
+
+```
+void drawBitmapRect(
+        const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint = nullptr) {
+    this->drawBitmapRectToRect(
+            bitmap, nullptr, dst, paint, kNone_DrawBitmapRectFlag);
+}
+```
+
+## Python
+
+Python code follows the [Google Python Style Guide](http://google-styleguide.googlecode.com/svn/trunk/pyguide.html).
diff --git a/site2/docs/dev/contrib/submit.md b/site2/docs/dev/contrib/submit.md
new file mode 100644
index 0000000..25ef7a3
--- /dev/null
+++ b/site2/docs/dev/contrib/submit.md
@@ -0,0 +1,244 @@
+
+---
+title: "How to submit a patch"
+linkTitle: "How to submit a patch"
+
+---
+
+
+
+Configure git
+-------------
+
+<!--?prettify lang=sh?-->
+
+    git config --global user.name "Your Name"
+    git config --global user.email you@example.com
+
+Making changes
+--------------
+
+First create a branch for your changes:
+
+<!--?prettify lang=sh?-->
+
+    git config branch.autosetuprebase always
+    git checkout -b my_feature origin/master
+
+After making your changes, create a commit
+
+<!--?prettify lang=sh?-->
+
+    git add [file1] [file2] ...
+    git commit
+
+If your branch gets out of date, you will need to update it:
+
+<!--?prettify lang=sh?-->
+
+    git pull
+    python2 tools/git-sync-deps
+
+Adding a unit test
+------------------
+
+If you are willing to change Skia codebase, it's nice to add a test at the same
+time. Skia has a simple unittest framework so you can add a case to it.
+
+Test code is located under the 'tests' directory.
+
+See [Writing Unit and Rendering Tests](../testing/tests) for details.
+
+Unit tests are best, but if your change touches rendering and you can't think of
+an automated way to verify the results, consider writing a GM test. Also, if your
+change is in the GPU code, you may not be able to write it as part of the standard
+unit test suite, but there are GPU-specific testing paths you can extend.
+
+Submitting a patch
+------------------
+
+For your code to be accepted into the codebase, you must complete the
+[Individual Contributor License
+Agreement](http://code.google.com/legal/individual-cla-v1.0.html). You can do
+this online, and it only takes a minute. If you are contributing on behalf of a
+corporation, you must fill out the [Corporate Contributor License
+Agreement](http://code.google.com/legal/corporate-cla-v1.0.html)
+and send it to us as described on that page. Add your (or your organization's)
+name and contact info to the AUTHORS file as a part of your CL.
+
+Now that you've made a change and written a test for it, it's ready for the code
+review! Submit a patch and getting it reviewed is fairly easy with depot tools.
+
+Use `git-cl`, which comes with [depot
+tools](http://sites.google.com/a/chromium.org/dev/developers/how-tos/install-depot-tools).
+For help, run `git cl help`.
+Note that in order for `git cl` to work correctly, it needs to run on a clone of
+<https://skia.googlesource.com/skia>. Using clones of mirrors, including Google's mirror
+on GitHub, might lead to issues with `git cl` usage.
+
+### Find a reviewer
+
+Ideally, the reviewer is someone who is familiar with the area of code you are
+touching. Look at the git blame for the file to see who else has been editing
+it. If unsuccessful, another option is to click on the 'Suggested Reviewers' button
+to add one of the listed Skia contacts. They should be able to add appropriate
+reviewers for your change. The button is located here:
+<img src="/dev/contrib/SuggestedReviewers.png" style="display: inline-block; max-width: 75%" />
+
+
+### Uploading changes for review
+
+Skia uses the Gerrit code review tool. Skia's instance is [skia-review](http://skia-review.googlesource.com).
+Use `git cl` to upload your change:
+
+<!--?prettify lang=sh?-->
+
+    git cl upload
+
+You may have to enter a Google Account username and password to authenticate
+yourself to Gerrit. A free gmail account will do fine, or any
+other type of Google account.  It does not have to match the email address you
+configured using `git config --global user.email` above, but it can.
+
+The command output should include a URL, similar to
+(https://skia-review.googlesource.com/c/4559/), indicating where your changelist
+can be reviewed.
+
+### Submit try jobs
+
+Skia's trybots allow testing and verification of changes before they land in the
+repo. You need to have permission to trigger try jobs; if you need permission,
+ask a committer. After uploading your CL to [Gerrit](https://skia-review.googlesource.com/),
+you may trigger a try job for any job listed in tasks.json, either via the
+Gerrit UI, using `git cl try`, eg.
+
+    git cl try -B skia.primary -b Some-Tryjob-Name
+
+or using bin/try, a small wrapper for `git cl try` which helps to choose try jobs.
+From a Skia checkout:
+
+    bin/try --list
+
+You can also search using regular expressions:
+
+    bin/try "Test.*GTX660.*Release"
+
+For more information about testing, see [testing infrastructure](https://skia.org/dev/testing/automated_testing).
+
+### Request review
+
+Go to the supplied URL or go to the code review page and select the **Your**
+dropdown and click on **Changes**. Select the change you want to submit for
+review and click **Reply**. Enter at least one reviewer's email address. Now
+add any optional notes, and send your change off for review by clicking on
+**Send**. Unless you send your change to reviewers, no one will know to look
+at it.
+
+_Note_: If you don't see editing commands on the review page, click **Sign in**
+in the upper right. _Hint_: You can add -r reviewer@example.com --send-mail to
+send the email directly when uploading a change using `git-cl`.
+
+
+The review process
+------------------
+
+If you submit a giant patch, or do a bunch of work without discussing it with
+the relevant people, you may have a hard time convincing anyone to review it!
+
+Code reviews are an important part of the engineering process. The reviewer will
+almost always have suggestions or style fixes for you, and it's important not to
+take such suggestions personally or as a commentary on your abilities or ideas.
+This is a process where we work together to make sure that the highest quality
+code gets submitted!
+
+You will likely get email back from the reviewer with comments. Fix these and
+update the patch set in the issue by uploading again. The upload will explain
+that it is updating the current CL and ask you for a message explaining the
+change. Be sure to respond to all comments before you request review of an
+update.
+
+If you need to update code the code on an already uploaded CL, simply edit the
+code, commit it again locally, and then run git cl upload again e.g.
+
+    echo "GOATS" > whitespace.txt
+    git add whitespace.txt
+    git commit -m 'add GOATS fix to whitespace.txt'
+    git cl upload
+
+Once you're ready for another review, use **Reply** again to send another
+notification (it is helpful to tell the reviewer what you did with respect to
+each of their comments). When the reviewer is happy with your patch, they will
+approve your change by setting the Code-Review label to "+1".
+
+_Note_: As you work through the review process, both you and your reviewers
+should converse using the code review interface, and send notes.
+
+Once your change has received an approval, you can click the "Submit to CQ"
+button on the codereview page and it will be committed on your behalf.
+
+Once your commit has gone in, you should delete the branch containing your change:
+
+    git checkout -q origin/master
+    git branch -D my_feature
+
+
+Final Testing
+-------------
+
+Skia's principal downstream user is Chromium, and any change to Skia rendering
+output can break Chromium. If your change alters rendering in any way, you are
+expected to test for and alleviate this. You may be able to find a Skia team
+member to help you, but the onus remains on each individual contributor to avoid
+breaking Chrome.
+
+### Evaluating Impact on Chromium
+
+Keep in mind that Skia is rolled daily into Blink and Chromium.  Run local tests
+and watch canary bots for results to ensure no impact.  If you are submitting
+changes that will impact layout tests, follow the guides below and/or work with
+your friendly Skia-Blink engineer to evaluate, rebaseline, and land your
+changes.
+
+Resources:
+
+[How to land Skia changes that change Blink layout test results](../chrome/layouttest)
+
+If you're changing the Skia API, you may need to make an associated change in Chromium.
+If you do, please follow these instructions: [Landing Skia changes which require Chrome changes](../chrome/changes)
+
+
+Check in your changes
+---------------------
+
+### Non-Skia-committers
+
+If you already have committer rights, you can follow the directions below to
+commit your change directly to Skia's repository.
+
+If you don't have committer rights in https://skia.googlesource.com/skia.git ...
+first of all, thanks for submitting your patch!  We really appreciate these
+submissions.  After receiving an approval from a committer, you will be able to
+click the "Submit to CQ" button and submit your patch via the commit queue.
+
+In special instances, a Skia committer may assist you in landing the change
+by uploading a new codereview containing your patch (perhaps with some small
+adjustments at their discretion).  If so, you can mark your change as
+"Abandoned", and update it with a link to the new codereview.
+
+### Skia committers
+  *  tips on how to apply an externally provided patch are [here](./patch)
+  *  when landing externally contributed patches, please note the original
+     contributor's identity (and provide a link to the original codereview) in the commit message
+
+    `git-cl` will squash all your commits into a single one with the description you used when you uploaded your change.
+
+    ~~~~
+    git cl land
+    ~~~~
+
+    or
+
+    ~~~~
+    git cl land -c 'Contributor Name <email@example.com>'
+    ~~~~
+
diff --git a/site2/docs/dev/design/_index.md b/site2/docs/dev/design/_index.md
new file mode 100644
index 0000000..820b777
--- /dev/null
+++ b/site2/docs/dev/design/_index.md
@@ -0,0 +1,12 @@
+
+---
+title: "Design Documents"
+linkTitle: "Design Documents"
+
+weight: 4
+
+---
+
+
+Public design documents for major efforts in Skia
+
diff --git a/site2/docs/dev/design/aaa.md b/site2/docs/dev/design/aaa.md
new file mode 100644
index 0000000..d861a38
--- /dev/null
+++ b/site2/docs/dev/design/aaa.md
@@ -0,0 +1,11 @@
+
+---
+title: "Analytic Anti-Alias"
+linkTitle: "Analytic Anti-Alias"
+
+---
+
+
+* [Analytic Anti-Alias Slides](https://docs.google.com/presentation/d/16r9HMS4_UBrcF3HUHscAqbSgkrtIwqaihZNwGP2TL_s/edit?usp=sharing)
+* [Analytic Anti-Alias Documents](https://docs.google.com/document/d/17Gq-huAf9q7wA4MRfXwpi_bYLrVeteKcSfAep0Am-wA/edit?usp=sharing)
+
diff --git a/site2/docs/dev/design/conical/_index.md b/site2/docs/dev/design/conical/_index.md
new file mode 100644
index 0000000..0f8978d
--- /dev/null
+++ b/site2/docs/dev/design/conical/_index.md
@@ -0,0 +1,331 @@
+---
+title: 'Two-point Conical Gradient'
+linkTitle: 'Two-point Conical Gradient'
+---
+
+<script type="text/x-mathjax-config">
+MathJax.Hub.Config({
+    tex2jax: {
+        inlineMath: [['$','$'], ['\\(','\\)']]
+    }
+});
+</script>
+
+<script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_CHTML'></script>
+
+(Please refresh the page if you see a lot of dollars instead of math symbols.)
+
+We present a fast shading algorithm (compared to bruteforcely solving the quadratic equation of
+gradient $t$) for computing the two-point conical gradient (i.e., `createRadialGradient` in
+[spec](https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-createradialgradient)).
+It reduced the number of multiplications per pixel from ~10 down to 3, and brought a speedup of up to
+26% in our nanobenches.
+
+This document has 3 parts:
+
+1. [Problem Statement and Setup](#problem-statement)
+2. [Algorithm](#algorithm)
+3. [Appendix](#appendix)
+
+Part 1 and 2 are self-explanatory. Part 3 shows how to geometrically proves our Theorem 1 in part
+2; it's more complicated but it gives us a nice picture about what's going on.
+
+## <span id="problem-statement">Problem Statement and Setup</span>
+
+Let two circles be $C_0, r_0$ and $C_1, r_1$ where $C$ is the center and $r$ is the radius. For any
+point $P = (x, y)$ we want the shader to quickly compute a gradient $t \in \mathbb R$ such that $p$
+is on the linearly interpolated circle with center $C_t = (1-t) \cdot C_0 + t \cdot C_1$ and radius
+$r_t = (1-t) \cdot r_0 + t \cdot r_1 > 0$ (note that radius $r_t$ has to be _positive_). If
+there are multiple (at most 2) solutions of $t$, choose the bigger one.
+
+There are two degenerated cases:
+
+1. $C_0 = C_1$ so the gradient is essentially a simple radial gradient.
+2. $r_0 = r_1$ so the gradient is a single strip with bandwidth $2 r_0 = 2 r_1$.
+
+<!-- TODO maybe add some fiddle or images here to illustrate the two degenerated cases -->
+
+They are easy to handle so we won't cover them here. From now on, we assume $C_0 \neq C_1$ and $r_0
+\neq r_1$.
+
+As $r_0 \neq r_1$, we can find a focal point $C_f = (1-f) \cdot C_0 + f \cdot C_1$ where its
+corresponding linearly interpolated radius $r_f = (1-f) \cdot r_0 + f \cdot r_1 = 0$.
+Solving the latter equation gets us $f = r_0 / (r_0 - r_1)$.
+
+As $C_0 \neq C_1$, focal point $C_f$ is different from $C_1$ unless $r_1 = 0$. If $r_1 = 0$, we can
+swap $C_0, r_0$ with $C_1, r_1$, compute swapped gradient $t_s$ as if $r_1 \neq 0$, and finally set
+$t = 1 - t_s$. The only catch here is that with multiple solutions of $t_s$, we shall choose the
+smaller one (so $t$ could be the bigger one).
+
+Assuming that we've done swapping if necessary so $C_1 \neq C_f$, we can then do a linear
+transformation to map $C_f, C_1$ to $(0, 0), (1, 0)$. After the transformation:
+
+1. All centers $C_t = (x_t, 0)$ must be on the $x$ axis
+2. The radius $r_t$ is $x_t r_1$.
+3. Given $x_t$ , we can derive $t = f + (1 - f) x_t$
+
+From now on, we'll focus on how to quickly computes $x_t$. Note that $r_t > 0$ so we're only
+interested positive solution $x_t$. Again, if there are multiple $x_t$ solutions, we may want to
+find the bigger one if $1 - f > 0$, and smaller one if $1 - f < 0$, so the corresponding $t$ is
+always the bigger one (note that $f \neq 1$, otherwise we'll swap $C_0, r_0$ with $C_1, r_1$).
+
+## <span id="algorithm">Algorithm</span>
+
+**Theorem 1.** The solution to $x_t$ is
+
+1. $\frac{x^2 + y^2}{(1 + r_1) x} = \frac{x^2 + y^2}{2 x}$ if $r_1 = 1$
+2. $\left(\sqrt{(r_1^2 - 1) y ^2 + r_1^2 x^2}  - x\right) / (r_1^2 - 1)$ if $r_1 > 1$
+3. $\left(\pm \sqrt{(r_1^2 - 1) y ^2 + r_1^2 x^2}  - x\right) / (r_1^2 - 1)$ if $r_1 < 1$.
+
+Case 2 always produces a valid $x_t$. Case 1 and 3 requires $x > 0$ to produce valid $x_t > 0$. Case
+3 may have no solution at all if $(r_1^2 - 1) y^2 + r_1^2 x^2 < 0$.
+
+_Proof._ Algebriacally, solving the quadratic equation $(x_t - x)^2 + y^2 = (x_t r_1)^2$ and
+eliminate negative $x_t$ solutions get us the theorem.
+
+Alternatively, we can also combine Corollary 2., 3., and Lemma 4. in the Appendix to geometrically
+prove the theorem. $\square$
+
+Theorem 1 by itself is not sufficient for our shader algorithm because:
+
+1. we still need to compute $t$ from $x_t$ (remember that $t = f + (1-f) x_t$);
+2. we still need to handle cases of choosing the bigger/smaller $x_t$;
+3. we still need to handle the swapped case (we swap $C_0, r_0$ with $C_1, r_1$ if $r_1 = 0$);
+4. there are way too many multiplications and divisions in Theorem 1 that would slow our shader.
+
+Issue 2 and 3 are solved by generating different shader code based on different situations. So they
+are mainly correctness issues rather than performance issues. Issue 1 and 4 are performance
+critical, and they will affect how we handle issue 2 and 3.
+
+The key to handle 1 and 4 efficiently is to fold as many multiplications and divisions into the
+linear transformation matrix, which the shader has to do anyway (remember our linear transformation
+to map $C_f, C_1$ to $(0, 0), (1, 0)$).
+
+For example, let $\hat x, \hat y = |1-f|x, |1-f|y$. Computing $\hat x_t$ with respect to $\hat x,
+\hat y$ allow us to have $t = f + (1 - f)x_t = f + \text{sign}(1-f) \cdot \hat x_t$. That saves us
+one multiplication. Applying similar techniques to Theorem 1 gets us:
+
+1. If $r_1 = 1$, let $x' = x/2,~ y' = y/2$, then $x_t = (x'^2 + y'^2) / x'$.
+2. If $r_1 > 1$, let $x' = r_1 / (r_1^2 - 1) x,~ y' = \frac{\sqrt{r_1^2 - 1}}{r_1^2 - 1} y$, then
+   $x_t = \sqrt{x'^2 + y'^2} - x' / r_1$
+3. If $r_1 < 1$, let $x' = r_1 / (r_1^2 - 1) x,~ y' = \frac{\sqrt{1 - r_1^2}}{r_1^2 - 1} y$, then
+   $x_t = \pm\sqrt{x'^2 - y'^2} - x' / r_1$
+
+Combining it with the swapping, the equation $t = f + (1-f) x_t$, and the fact that we only want
+positive $x_t > 0$ and bigger $t$, we have our final algorithm:
+
+**Algorithm 1.**
+
+1. Let $C'_0, r'_0, C'_1, r'_1 = C_0, r_0, C_1, r_1$ if there is no swapping and $C'_0,
+    r'_0, C'_1, r'_1 = C_1, r_1, C_0, r_0$ if there is swapping.
+2. Let $f = r'_0 / (r'_0 - r'_1)$ and $1 - f = r'_1 / (r'_1 - r'_0)$
+3. Let $x' = x/2,~ y' = y/2$ if $r_1 = 1$, and
+   $x' = r_1 / (r_1^2 - 1) x,~ y' = \sqrt{|r_1^2 - 1|} / (r_1^2 - 1) y$ if $r_1 \neq 1$
+4. Let $\hat x = |1 - f|x', \hat y = |1 - f|y'$
+5. If $r_1 = 1$, let $\hat x_t = (\hat x^2 + \hat y^2) / \hat x$
+6. If $r_1 > 1$,
+   let $\hat x_t = \sqrt{\hat x^2 + \hat y^2} - \hat x / r_1$
+7. If $r_1 < 1$
+8. return invalid if $\hat x^2 - \hat y^2 < 0$
+9. let $\hat x_t =  -\sqrt{\hat x^2 - \hat y^2} - \hat x / r_1$ if we've swapped $r_0, r_1$,
+   or if $1 - f < 0$
+
+10. let $\hat x_t =  \sqrt{\hat x^2 - \hat y^2} - \hat x / r_1$ otherwise
+
+11. $t$ is invalid if $\hat x_t < 0$ (this check is unnecessary if $r_1 > 1$)
+12. Let $t = f + \text{sign}(1 - f) \hat x_t$
+13. If swapped, let $t = 1 - t$
+
+In step 7, we try to select either the smaller or bigger $\hat x_t$ based on whether the final $t$
+has a negative or positive relationship with $\hat x_t$. It's negative if we've swapped, or if
+$\text{sign}(1 - f)$ is negative (these two cannot both happen).
+
+Note that all the computations and if decisions not involving $\hat x, \hat y$ can be precomputed
+before the shading stage. The two if decisions $\hat x^2 - \hat y^2 < 0$ and $\hat x^t < 0$ can
+also be omitted by precomputing the shading area that never violates those conditions.
+
+The number of operations per shading is thus:
+
+- 1 addition, 2 multiplications, and 1 division if $r_1 = 1$
+- 2 additions, 3 multiplications, and 1 sqrt for $r_1 \neq 1$ (count subtraction as addition;
+  dividing $r_1$ is multiplying $1/r_1$)
+- 1 more addition operation if $f \neq 0$
+- 1 more addition operation if swapped.
+
+In comparison, for $r_1 \neq 1$ case, our current raster pipeline shading algorithm (which shall
+hopefully soon be upgraded to the algorithm described here) mainly uses formula $$t = 0.5 \cdot
+(1/a) \cdot \left(-b \pm \sqrt{b^2 - 4ac}\right)$$ It precomputes $a = 1 - (r_1 - r_0)^2, 1/a, r1 -
+r0$. Number $b = -2 \cdot (x + (r1 - r0) \cdot r0)$ costs 2 multiplications and 1 addition. Number
+$c = x^2 + y^2 - r_0^2$ costs 3 multiplications and 2 additions. And the final $t$ costs 5 more
+multiplications, 1 more sqrt, and 2 more additions. That's a total of 5 additions, 10
+multiplications, and 1 sqrt. (Our algorithm has 2-4 additions, 3 multiplications, and 1 sqrt.) Even
+if it saves the $0.5 \cdot (1/a), 4a, r_0^2$ and $(r_1 - r_0) r_0$ multiplications, there are still
+6 multiplications. Moreover, it sends in 4 unitofmrs to the shader while our algorithm only needs 2
+uniforms ($1/r_1$ and $f$).
+
+## <span id="appendix">Appendix</span>
+
+**Lemma 1.** Draw a ray from $C_f = (0, 0)$ to $P = (x, y)$. For every
+intersection points $P_1$ between that ray and circle $C_1 = (1, 0), r_1$, there exists an $x_t$
+that equals to the length of segment $C_f P$ over length of segment $C_f P_1$. That is,
+$x_t = || C_f P || / ||C_f P_1||$
+
+_Proof._ Draw a line from $P$ that's parallel to $C_1 P_1$. Let it intersect with $x$-axis on point
+$C = (x', y')$.
+
+<img src="conical/lemma1.svg"/>
+
+Triangle $\triangle C_f C P$ is similar to triangle $\triangle C_f C_1 P_1$.
+Therefore $||P C|| = ||P_1 C_1|| \cdot (||C_f C|| / ||C_f C_1||) = r_1 x'$. Thus $x'$ is a solution
+to $x_t$. Because triangle $\triangle C_f C P$ and triangle $\triangle C_f C_1 P_1$ are similar, $x'
+= ||C_f C_1|| \cdot (||C_f P|| / ||C_f P_1||) = ||C_f P|| / ||C_f P_1||$. $\square$
+
+**Lemma 2.** For every solution $x_t$, if we extend/shrink segment $C_f P$ to $C_f P_1$ with ratio
+$1 / x_t$ (i.e., find $P_1$ on ray $C_f P$ such that $||C_f P_1|| / ||C_f P|| = 1 / x_t$), then
+$P_1$ must be on circle $C_1, r_1$.
+
+_Proof._ Let $C_t = (x_t, 0)$. Triangle $\triangle C_f C_t P$ is similar to $C_f C_1 P_1$. Therefore
+$||C_1 P_1|| = r_1$ and $P_1$ is on circle $C_1, r_1$. $\square$
+
+**Corollary 1.** By lemma 1. and 2., we conclude that the number of solutions $x_t$ is equal to the
+number of intersections between ray $C_f P$ and circle $C_1, r_1$. Therefore
+
+- when $r_1 > 1$, there's always one unique intersection/solution; we call this "well-behaved"; this
+  was previously known as the "inside" case;
+- when $r_1 = 1$, there's either one or zero intersection/solution (excluding $C_f$ which is always
+  on the circle); we call this "focal-on-circle"; this was previously known as the "edge" case;
+
+<img src="conical/corollary2.2.1.svg"/>
+<img src="conical/corollary2.2.2.svg"/>
+
+- when $r_1 < 1$, there may be $0, 1$, or $2$ solutions; this was also previously as the "outside"
+  case.
+
+<img src="conical/corollary2.3.1.svg" width="30%"/>
+<img src="conical/corollary2.3.2.svg" width="30%"/>
+<img src="conical/corollary2.3.3.svg" width="30%"/>
+
+**Lemma 3.** When solution exists, one such solution is
+
+$$
+    x_t = {|| C_f P || \over ||C_f P_1||} = \frac{x^2 + y^2}{x + \sqrt{(r_1^2 - 1) y^2 + r_1^2 x^2}}
+$$
+
+_Proof._ As $C_f = (0, 0), P = (x, y)$, we have $||C_f P|| = \sqrt(x^2 + y^2)$. So we'll mainly
+focus on how to compute $||C_f P_1||$.
+
+**When $x \geq 0$:**
+
+<img src="conical/lemma3.1.svg"/>
+
+Let $X_P = (x, 0)$ and $H$ be a point on $C_f P_1$ such that $C_1 H$ is perpendicular to $C_1
+P_1$. Triangle $\triangle C_1 H C_f$ is similar to triangle $\triangle P X_P C_f$. Thus
+$$||C_f H|| = ||C_f C_1|| \cdot (||C_f X_P|| / ||C_f P||) = x / \sqrt{x^2 + y^2}$$
+$$||C_1 H|| = ||C_f C_1|| \cdot (||P X_P|| / ||C_f P||) = y / \sqrt{x^2 + y^2}$$
+
+Triangle $\triangle C_1 H P_1$ is a right triangle with hypotenuse $r_1$. Hence
+$$ ||H P_1|| = \sqrt{r_1^2 - ||C_1 H||^2} = \sqrt{r_1^2 - y^2 / (x^2 + y^2)} $$
+
+We have
+\begin{align}
+||C_f P_1|| &= ||C_f H|| + ||H P_1|| \\\\\\
+&= x / \sqrt{x^2 + y^2} + \sqrt{r_1^2 - y^2 / (x^2 + y^2)} \\\\\\
+&= \frac{x + \sqrt{r_1^2 (x^2 + y^2) - y^2}}{\sqrt{x^2 + y^2}} \\\\\\
+&= \frac{x + \sqrt{(r_1^2 - 1) y^2 + r_1^2 x^2}}{\sqrt{x^2 + y^2}}
+\end{align}
+
+**When $x < 0$:**
+
+Define $X_P$ and $H$ similarly as before except that now $H$ is on ray $P_1 C_f$ instead of
+$C_f P_1$.
+
+<img src="conical/lemma3.2.svg"/>
+
+As before, triangle $\triangle C_1 H C_f$ is similar to triangle $\triangle P X_P C_f$, and triangle
+$\triangle C_1 H P_1$ is a right triangle, so we have
+$$||C_f H|| = ||C_f C_1|| \cdot (||C_f X_P|| / ||C_f P||) = -x / \sqrt{x^2 + y^2}$$
+$$||C_1 H|| = ||C_f C_1|| \cdot (||P X_P|| / ||C_f P||) = y / \sqrt{x^2 + y^2}$$
+$$ ||H P_1|| = \sqrt{r_1^2 - ||C_1 H||^2} = \sqrt{r_1^2 - y^2 / (x^2 + y^2)} $$
+
+Note that the only difference is changing $x$ to $-x$ because $x$ is negative.
+
+Also note that now $||C_f P_1|| = -||C_f H|| + ||H P_1||$ and we have $-||C_f H||$ instead of
+$||C_f H||$. That negation cancels out the negation of $-x$ so we get the same equation
+of $||C_f P_1||$ for both $x \geq 0$ and $x < 0$ cases:
+
+$$
+    ||C_f P_1|| = \frac{x + \sqrt{(r_1^2 - 1) y^2 + r_1^2 x^2}}{\sqrt{x^2 + y^2}}
+$$
+
+Finally
+
+$$
+    x_t = \frac{||C_f P||}{||C_f P_1||} = \frac{\sqrt{x^2 + y^2}}{||C_f P_1||}
+        = \frac{x^2 + y^2}{x + \sqrt{(r_1^2 - 1) y^2 + r_1^2 x^2}}
+$$ $\square$
+
+**Corollary 2.** If $r_1 = 1$, then the solution $x_t = \frac{x^2 + y^2}{(1 + r_1) x}$, and
+it's valid (i.e., $x_t > 0$) iff $x > 0$.
+
+*Proof.* Simply plug $r_1 = 1$ into the formula of Lemma 3. $\square$
+
+**Corollary 3.** If $r_1 > 1$, then the unique solution is
+$x_t = \left(\sqrt{(r_1^2 - 1) y ^2 + r_1^2 x^2}  - x\right) / (r_1^2 - 1)$.
+
+*Proof.* From Lemma 3., we have
+
+\begin{align}
+    x_t &= \frac{x^2 + y^2}{x + \sqrt{(r_1^2 - 1) y^2 + r_1^2 x^2}} \\\\\\
+        &=  {
+                (x^2 + y^2) \left ( -x + \sqrt{(r_1^2 - 1) y^2 + r_1^2 x^2} \right )
+            \over
+                \left (x + \sqrt{(r_1^2 - 1) y^2 + r_1^2 x^2} \right )
+                \left (-x + \sqrt{(r_1^2 - 1) y^2 + r_1^2 x^2} \right )
+            } \\\\\\
+        &=  {
+                (x^2 + y^2) \left ( -x + \sqrt{(r_1^2 - 1) y^2 + r_1^2 x^2} \right )
+            \over
+                -x^2 + (r_1^2 - 1) y^2 + r_1^2 x^2
+            } \\\\\\
+        &=  {
+                (x^2 + y^2) \left ( -x + \sqrt{(r_1^2 - 1) y^2 + r_1^2 x^2} \right )
+            \over
+                (r_1^2 - 1) (x^2 + y^2)
+            } \\\\\\
+        &=  \left(\sqrt{(r_1^2 - 1) y ^2 + r_1^2 x^2}  - x\right) / (r_1^2 - 1)
+\end{align}
+
+The transformation above (multiplying $-x + \sqrt{(r_1^2 - 1) y^2 + r_1^2 x^2}$ to enumerator and
+denomenator) is always valid because $r_1 > 1$ and it's the unique solution due to Corollary 1.
+$\square$
+
+**Lemma 4.** If $r_1 < 1$, then
+
+1. there's no solution to $x_t$ if $(r_1^2 - 1) y^2 + r_1^2 x^2 < 0$
+2. otherwise, the solutions are
+    $x_t = \left(\sqrt{(r_1^2 - 1) y ^2 + r_1^2 x^2}  - x\right) / (r_1^2 - 1)$,
+    or
+    $x_t = \left(-\sqrt{(r_1^2 - 1) y ^2 + r_1^2 x^2}  - x\right) / (r_1^2 - 1)$.
+
+(Note that solution $x_t$ still has to be nonnegative to be valid; also note that
+$x_t > 0 \Leftrightarrow x > 0$ if the solution exists.)
+
+*Proof.* Case 1 follows naturally from Lemma 3. and Corollary 1.
+
+<img src="conical/lemma4.svg"/>
+
+For case 2, we notice that $||C_f P_1||$ could be
+
+1. either $||C_f H|| + ||H P_1||$ or $||C_f H|| - ||H P_1||$ if $x \geq 0$,
+2. either $-||C_f H|| + ||H P_1||$ or $-||C_f H|| - ||H P_1||$ if $x < 0$.
+
+By analysis similar to Lemma 3., the solution to $x_t$ does not depend on the sign of $x$ and
+they are either $\frac{x^2 + y^2}{x + \sqrt{(r_1^2 - 1) y^2 + r_1^2 x^2}}$
+or $\frac{x^2 + y^2}{x - \sqrt{(r_1^2 - 1) y^2 + r_1^2 x^2}}$.
+
+As $r_1 \neq 1$, we can apply the similar transformation in Corollary 3. to get the two
+formula in the lemma.
+$\square$
+
+
+$$
diff --git a/site2/docs/dev/design/pdftheory.md b/site2/docs/dev/design/pdftheory.md
new file mode 100644
index 0000000..c54daa9
--- /dev/null
+++ b/site2/docs/dev/design/pdftheory.md
@@ -0,0 +1,453 @@
+---
+title: 'PDF Theory of Operation'
+linkTitle: 'PDF Theory of Operation'
+---
+
+<!--
+PRE-GIT DOCUMENT VERSION HISTORY
+    2012-06-25 Steve VanDeBogart
+               * Original version
+    2015-01-14 Hal Canary.
+               * Add section "Using the PDF backend"
+               * Markdown formatting
+-->
+
+Internally, SkPDFDocument and SkPDFDevice represents PDF documents and pages.
+This document describes how the backend operates, but **these interfaces are not
+part of the public API and are subject to perpetual change.**
+
+See [Using Skia's PDF Backend](../../user/sample/pdf) to find out how to use
+SkPDF as a client calling Skia's public API.
+
+---
+
+### Contents
+
+- [Typical usage of the PDF backend](#Typical_usage_of_the_PDF_backend)
+- [PDF Objects and Document Structure](#PDF_Objects_and_Document_Structure)
+- [PDF drawing](#PDF_drawing)
+- [Interned objects](#Interned_objects)
+- [Graphic States](#Graphic_States)
+- [Clip and Transform](#Clip_and_Transform)
+- [Generating a content stream](#Generating_a_content_stream)
+- [Drawing details](#Drawing_details)
+  - [Layers](#Layers)
+  - [Fonts](#Fonts)
+  - [Shaders](#Shaders)
+  - [Xfer modes](#Xfer_modes)
+- [Known issues](#Known_issues)
+
+## <span id="Typical_usage_of_the_PDF_backend">Typical usage of the PDF backend</span>
+
+SkPDFDevice is the main interface to the PDF backend. This child of SkDevice can
+be set on an SkCanvas and drawn to. Once drawing to the canvas is complete
+(SkDocument::onEndPage() is called), the device's content and resources are
+added to the SkPDFDocument that owns the device. A new SkPDFDevice should be
+created for each page or layer desired in the document. After all the pages have
+been added to the document, `SkPDFDocument::onClose()` is called to finish
+serializing the PDF file.
+
+## <span id="PDF_Objects_and_Document_Structure">PDF Objects and Document Structure</span>
+
+![PDF Logical Document Structure](/dev/design/PdfLogicalDocumentStructure.png)
+
+**Background**: The PDF file format has a header, a set of objects and then a
+footer that contains a table of contents for all of the objects in the document
+(the cross-reference table). The table of contents lists the specific byte
+position for each object. The objects may have references to other objects and
+the ASCII size of those references is dependent on the object number assigned to
+the referenced object; therefore we can't calculate the table of contents until
+the size of objects is known, which requires assignment of object numbers. The
+document uses SkWStream::bytesWritten() to query the offsets of each object and
+build the cross-reference table.
+
+Furthermore, PDF files can support a _linearized_ mode, where objects are in a
+specific order so that pdf-viewers can more easily retrieve just the objects
+they need to display a specific page, i.e. by byte-range requests over the web.
+Linearization also requires that all objects used or referenced on the first
+page of the PDF have object numbers before the rest of the objects.
+Consequently, before generating a linearized PDF, all objects, their sizes, and
+object references must be known. Skia has no plans to implement linearized PDFs.
+
+    %PDF-1.4
+    …objects...
+    xref
+    0 31  % Total number of entries in the table of contents.
+    0000000000 65535 f
+    0000210343 00000 n
+    …
+    0000117055 00000 n
+    trailer
+    <</Size 31 /Root 1 0 R>>
+    startxref
+    210399  % Byte offset to the start of the table of contents.
+    %%EOF
+
+The the virtual class SkPDFObject are used to manage the needs of the file
+format. Any object that will represent a PDF object must inherit from
+SkPDFObject and implement the methods to generate the binary representation and
+report any other SkPDFObjects used as resources. SkPDFTypes.h defines most of
+the basic PDF object types: bool, int, scalar, string, name, array, dictionary,
+and stream. (A stream is a dictionary containing at least a Length entry
+followed by the data of the stream.)
+
+Streams are now handled in a slightly different way. The SkPDFStreamOut()
+function compresses and serializes the binary data immediately instead of
+creating a new object.
+
+All of these PDF object types except the stream type can be used in both a
+direct and an indirect fashion, i.e. an array can have an int or a dictionary as
+an inline entry, which does not require an object number. The stream type,
+cannot be inlined and must be referred to with an object reference. Most of the
+time, other objects types can be referred to with an object reference, but there
+are specific rules in the PDF specification that requires an inline reference in
+some place or an indirect reference in other places. All indirect objects must
+have an object number assigned.
+
+- **bools**: `true` `false`
+- **ints**: `42` `0` `-1`
+- **scalars**: `0.001`
+- **strings**: `(strings are in parentheses or byte encoded)` `<74657374>`
+- **name**: `/Name` `/Name#20with#20spaces`
+- **array**: `[/Foo 42 (arrays can contain multiple types)]`
+- **dictionary**: `<</Key1 (value1) /key2 42>>`
+- **indirect object**:  
+  `5 0 obj (An indirect string. Indirect objects have an object number and a generation number, Skia always uses generation 0 objects) endobj`
+- **object reference**: `5 0 R`
+- **stream**:
+  `<</Length 56>> stream ...stream contents can be arbitrary, including binary... endstream`
+
+Indirect objects are either:
+
+- Serialized as soon as they are needed, and a new SkPDFIndirectReference is
+  returned, or
+
+- Serialized later, but reserve a document-unique SkPDFIndirectReference to
+  allow other objects to refer to it.
+
+Example document:
+
+    %PDF-1.4
+    2 0 obj <<
+      /Type /Catalog
+      /Pages 1 0 R
+    >>
+    endobj
+    3 0 obj <<
+      /Type /Page
+      /Parent 1 0 R
+      /Resources <>
+      /MediaBox [0 0 612 792]
+      /Contents 4 0 R
+    >>
+    endobj
+    4 0 obj <> stream
+    endstream
+    endobj
+    1 0 obj <<
+      /Type /Pages
+      /Kids [3 0 R]
+      /Count 1
+    >>
+    endobj
+    xref
+    0 5
+    0000000000 65535 f
+    0000000236 00000 n
+    0000000009 00000 n
+    0000000062 00000 n
+    0000000190 00000 n
+    trailer
+    <</Size 5 /Root 2 0 R>>
+    startxref
+    299
+    %%EOF
+
+## <span id="PDF_drawing">PDF drawing</span>
+
+Most drawing in PDF is specified by the text of a stream, referred to as a
+content stream. The syntax of the content stream is different than the syntax of
+the file format described above and is much closer to PostScript in nature. The
+commands in the content stream tell the PDF interpreter to draw things, like a
+rectangle (`x y w h re`), an image, or text, or to do meta operations like set
+the drawing color, apply a transform to the drawing coordinates, or clip future
+drawing operations. The page object that references a content stream has a list
+of resources that can be used in the content stream using the dictionary name to
+reference the resources. Resources are things like font objects, images objects,
+graphic state objects (a set of meta operations like miter limit, line width,
+etc). Because of a mismatch between Skia and PDF’s support for transparency
+(which will be explained later), SkPDFDevice records each drawing operation into
+an internal structure (ContentEntry) and only when the content stream is needed
+does it flatten that list of structures into the final content stream.
+
+    4 0 obj <<
+      /Type /Page
+      /Resources <<
+        /Font <</F1 9 0 R>>
+        /XObject <</Image1 22 0 R /Image2 73 0 R>>
+      >>
+      /Content 5 0 R
+    >> endobj
+
+    5 0 obj <</Length 227>> stream
+    % In the font specified in object 9 and a height
+    % of 12 points, at (72, 96) draw ‘Hello World.’
+    BT
+      /F1 12 Tf
+      72 96 Td
+      (Hello World) Tj
+    ET
+    % Draw a filled rectange.
+    200 96 72 72 re B
+    ...
+    endstream
+    endobj
+
+## <span id="Interned_objects">Interned objects</span>
+
+There are a number of high level PDF objects (like fonts, graphic states, etc)
+that are likely to be referenced multiple times in a single PDF. To ensure that
+there is only one copy of each object, the SkPDFDocument holds on to a mapping
+from type-specific keys onto the SkPDFIndirectReference for these objects.
+
+## <span id="Graphic_States">Graphic States</span>
+
+PDF has a number of parameters that affect how things are drawn. The ones that
+correspond to drawing options in Skia are: color, alpha, line cap, line join
+type, line width, miter limit, and xfer/blend mode (see later section for xfer
+modes). With the exception of color, these can all be specified in a single pdf
+object, represented by the SkPDFGraphicState class. A simple command in the
+content stream can then set the drawing parameters to the values specified in
+that graphic state object. PDF does not allow specifying color in the graphic
+state object, instead it must be specified directly in the content stream.
+Similarly the current font and font size are set directly in the content stream.
+
+    6 0 obj <<
+      /Type /ExtGState
+      /CA 1  % Opaque - alpha = 1
+      /LC 0  % Butt linecap
+      /LJ 0  % Miter line-join
+      /LW 2  % Line width of 2
+      /ML 6  % Miter limit of 6
+      /BM /Normal  % Blend mode is normal i.e. source over
+    >>
+    endobj
+
+## <span id="Clip_and_Transform">Clip and Transform</span>
+
+Similar to Skia, PDF allows drawing to be clipped or transformed. However, there
+are a few caveats that affect the design of the PDF backend. PDF does not
+support perspective transforms (perspective transform are treated as identity
+transforms). Clips, however, have more issues to cotend with. PDF clips cannot
+be directly unapplied or expanded. i.e. once an area has been clipped off, there
+is no way to draw to it. However, PDF provides a limited depth stack for the PDF
+graphic state (which includes the drawing parameters mentioned above in the
+Graphic States section as well as the clip and transform). Therefore to undo a
+clip, the PDF graphic state must be pushed before the clip is applied, then
+popped to revert to the state of the graphic state before the clip was applied.
+
+As the canvas makes drawing calls into SkPDFDevice, the active transform, clip
+region, and clip stack are stored in a ContentEntry structure. Later, when the
+ContentEntry structures are flattened into a valid PDF content stream, the
+transforms and clips are compared to decide on an efficient set of operations to
+transition between the states needed. Currently, a local optimization is used,
+to figure out the best transition from one state to the next. A global
+optimization could improve things by more effectively using the graphics state
+stack provided in the PDF format.
+
+## <span id="Generating_a_content_stream">Generating a content stream</span>
+
+For each draw call on an SkPDFDevice, a new ContentEntry is created, which
+stores the matrix, clip region, and clip stack as well as the paint parameters.
+Most of the paint parameters are bundled into an SkPDFGraphicState (interned)
+with the rest (color, font size, etc) explicitly stored in the ContentEntry.
+After populating the ContentEntry with all the relevant context, it is compared
+to the the most recently used ContentEntry. If the context matches, then the
+previous one is appended to instead of using the new one. In either case, with
+the context populated into the ContentEntry, the appropriate draw call is
+allowed to append to the content stream snippet in the ContentEntry to affect
+the core of the drawing call, i.e. drawing a shape, an image, text, etc.
+
+When all drawing is complete, SkPDFDocument::onEndPage() will call
+SkPDFDevice::content() to request the complete content stream for the page. The
+first thing done is to apply the initial transform specified in part in the
+constructor, this transform takes care of changing the coordinate space from an
+origin in the lower left (PDF default) to the upper left (Skia default) as well
+as any translation or scaling requested by the user (i.e. to achieve a margin or
+scale the canvas). Next (well almost next, see the next section), a clip is
+applied to restrict drawing to the content area (the part of the page inside the
+margins) of the page. Then, each ContentEntry is applied to the content stream
+with the help of a helper class, GraphicStackState, which tracks the state of
+the PDF graphics stack and optimizes the output. For each ContentEntry, commands
+are emitted to the final content entry to update the clip from its current state
+to the state specified in the ContentEntry, similarly the Matrix and drawing
+state (color, line joins, etc) are updated, then the content entry fragment (the
+actual drawing operation) is appended.
+
+## <span id="Drawing_details">Drawing details</span>
+
+Certain objects have specific properties that need to be dealt with. Images,
+layers (see below), and fonts assume the standard PDF coordinate system, so we
+have to undo any flip to the Skia coordinate system before drawing these
+entities. We don't currently support inverted paths, so filling an inverted path
+will give the wrong result ([issue 241](https://bug.skia.org/241)). PDF doesn't
+draw zero length lines that have butt of square caps, so that is emulated.
+
+### <span id="Layers">Layers</span>
+
+PDF has a higher level object called a form x-object (form external object) that
+is basically a PDF page, with resources and a content stream, but can be
+transformed and drawn on an existing page. This is used to implement layers.
+SkPDFDevice has a method, makeFormXObjectFromDevice(), which uses the
+SkPDFDevice::content() method to construct a form x-object from the the device.
+SkPDFDevice::drawDevice() works by creating a form x-object of the passed device
+and then drawing that form x-object in the root device. There are a couple
+things to be aware of in this process. As noted previously, we have to be aware
+of any flip to the coordinate system - flipping it an even number of times will
+lead to the wrong result unless it is corrected for. The SkClipStack passed to
+drawing commands includes the entire clip stack, including the clipping
+operations done on the base layer. Since the form x-object will be drawn as a
+single operation onto the base layer, we can assume that all of those clips are
+in effect and need not apply them within the layer.
+
+### <span id="Fonts">Fonts</span>
+
+There are many details for dealing with fonts, so this document will only talk
+about some of the more important ones. A couple short details:
+
+- We can't assume that an arbitrary font will be available at PDF view time, so
+  we embed all fonts in accordance with modern PDF guidelines.
+- Most fonts these days are TrueType fonts, so this is where most of the effort
+  has been concentrated.
+- Because Skia may only be given a glyph-id encoding of the text to render and
+  there is no perfect way to reverse the encoding, the PDF backend always uses
+  the glyph-id encoding of the text.
+
+#### _Type1/Type3 fonts_
+
+Linux supports Type1 fonts, but Windows and Mac seem to lack the functionality
+required to extract the required information from the font without parsing the
+font file. When a non TrueType font is used any any platform (except for Type1
+on Linux), it is encoded as a Type3 font. In this context, a Type3 font is an
+array of form x-objects (content streams) that draw each glyph of the font. No
+hinting or kerning information is included in a Type3 font, just the shape of
+each glyph. Any font that has the do-not embed copy protection bit set will also
+get embedded as a Type3 font. From what I understand, shapes are not
+copyrightable, but programs are, so by stripping all the programmatic
+information and only embedding the shape of the glyphs we are honoring the
+do-not embed bit as much as required by law.
+
+PDF only supports an 8-bit encoding for Type1 or Type3 fonts. However, they can
+contain more than 256 glyphs. The PDF backend handles this by segmenting the
+glyphs into groups of 255 (glyph id 0 is always the unknown glyph) and
+presenting the font as multiple fonts, each with up to 255 glyphs.
+
+#### _Font subsetting_
+
+Many fonts, especially fonts with CJK support are fairly large, so it is
+desirable to subset them. Chrome uses the SFNTLY package to provide subsetting
+support to Skia for TrueType fonts.
+
+### <span id="Shaders">Shaders</span>
+
+Skia has two types of predefined shaders, image shaders and gradient shaders. In
+both cases, shaders are effectively positioned absolutely, so the initial
+position and bounds of where they are visible is part of the immutable state of
+the shader object. Each of the Skia's tile modes needs to be considered and
+handled explicitly. The image shader we generate will be tiled, so tiling is
+handled by default. To support mirroring, we draw the image, reversed, on the
+appropriate axis, or on both axes plus a fourth in the vacant quadrant. For
+clamp mode, we extract the pixels along the appropriate edge and stretch the
+single pixel wide/long image to fill the bounds. For both x and y in clamp mode,
+we fill the corners with a rectangle of the appropriate color. The composed
+shader is then rotated or scaled as appropriate for the request.
+
+Gradient shaders are handled purely mathematically. First, the matrix is
+transformed so that specific points in the requested gradient are at pre-defined
+locations, for example, the linear distance of the gradient is always normalized
+to one. Then, a type 4 PDF function is created that achieves the desired
+gradient. A type 4 function is a function defined by a resticted postscript
+language. The generated functions clamp at the edges so if the desired tiling
+mode is tile or mirror, we hav to add a bit more postscript code to map any
+input parameter into the 0-1 range appropriately. The code to generate the
+postscript code is somewhat obtuse, since it is trying to generate optimized
+(for space) postscript code, but there is a significant number of comments to
+explain the intent.
+
+### <span id="Xfer_modes">Xfer modes</span>
+
+PDF supports some of the xfer modes used in Skia directly. For those, it is
+simply a matter of setting the blend mode in the graphic state to the
+appropriate value (Normal/SrcOver, Multiply, Screen, Overlay, Darken, Lighten,
+!ColorDOdge, ColorBurn, HardLight, SoftLight, Difference, Exclusion). Aside from
+the standard SrcOver mode, PDF does not directly support the porter-duff xfer
+modes though. Most of them (Clear, SrcMode, DstMode, DstOver, SrcIn, DstIn,
+SrcOut, DstOut) can be emulated by various means, mostly by creating form
+x-objects out of part of the content and drawing it with a another form x-object
+as a mask. I have not figured out how to emulate the following modes: SrcATop,
+DstATop, Xor, Plus.
+
+At the time of writing [2012-06-25], I have a
+[CL outstanding to fix a misunderstanding I had about the meaning of some of the emulated modes](https://codereview.appspot.com/4631078/).
+I will describe the system with this change applied.
+
+First, a bit of terminology and definition. When drawing something with an
+emulated xfer mode, what's already drawn to the device is called the destination
+or Dst, and what's about to be drawn is the source or Src. Src (and Dst) can
+have regions where it is transparent (alpha equals zero), but it also has an
+inherent shape. For most kinds of drawn objects, the shape is the same as where
+alpha is not zero. However, for things like images and layers, the shape is the
+bounds of the item, not where the alpha is non-zero. For example, a 10x10 image,
+that is transparent except for a 1x1 dot in the center has a shape that is
+10x10. The xfermodes gm test demonstrates the interaction between shape and
+alpha in combination with the port-duff xfer modes.
+
+The clear xfer mode removes any part of Dst that is within Src's shape. This is
+accomplished by bundling the current content of the device (Dst) into a single
+entity and then drawing that with the inverse of Src's shape used as a mask (we
+want Dst where Src isn't). The implementation of that takes a couple more steps.
+You may have to refer back to
+[the content stream section](#Generating_a_content_stream). For any draw call, a
+ContentEntry is created through a method called
+SkPDFDevice::setUpContentEntry(). This method examines the xfer modes in effect
+for that drawing operation and if it is an xfer mode that needs emulation, it
+creates a form x-object from the device, i.e. creates Dst, and stores it away
+for later use. This also clears all of that existing ContentEntry's on that
+device. The drawing operation is then allowed to proceed as normal (in most
+cases, see note about shape below), but into the now empty device. Then, when
+the drawing operation in done, a complementary method is
+called,SkPDFDevice::finishContentEntry(), which takes action if the current xfer
+mode is emulated. In the case of Clear, it packages what was just drawn into
+another form x-object, and then uses the Src form x-object, an invert function,
+and the Dst form x-object to draw Dst with the inverse shape of Src as a mask.
+This works well when the shape of Src is the same as the opaque part of the
+drawing, since PDF uses the alpha channel of the mask form x-object to do
+masking. When shape doesn't match the alpha channel, additional action is
+required. The drawing routines where shape and alpha don't match, set state to
+indicate the shape (always rectangular), which finishContentEntry uses. The
+clear xfer mode is a special case; if shape is needed, then Src isn't used, so
+there is code to not bother drawing Src if shape is required and the xfer mode
+is clear.
+
+SrcMode is clear plus Src being drawn afterward. DstMode simply omits drawing
+Src. DstOver is the same as SrcOver with Src and Dst swapped - this is
+accomplished by inserting the new ContentEntry at the beginning of the list of
+ContentEntry's in setUpContentEntry instead of at the end. SrcIn, SrcOut, DstIn,
+DstOut are similar to each, the difference being an inverted or non-inverted
+mask and swapping Src and Dst (or not). SrcIn is SrcMode with Src drawn with Dst
+as a mask. SrcOut is like SrcMode, but with Src drawn with an inverted Dst as a
+mask. DstIn is SrcMode with Dst drawn with Src as a mask. Finally, DstOut is
+SrcMode with Dst draw with an inverted Src as a mask.
+
+## <span id="Known_issues">Known issues</span>
+
+- [issue 249](https://bug.skia.org/249) SrcAtop Xor, and Plus xfer modes are not
+  supported.
+- [issue 240](https://bug.skia.org/240) drawVerticies is not implemented.
+- [issue 244](https://bug.skia.org/244) Mostly, only TTF fonts are _directly_
+  supported. (User metrics show that almost all fonts are truetype.)
+- [issue 260](https://bug.skia.org/260) Page rotation is accomplished by
+  specifying a different size page instead of including the appropriate rotation
+  annotation.
+
+---
diff --git a/site2/docs/dev/design/raster_tragedy/_index.md b/site2/docs/dev/design/raster_tragedy/_index.md
new file mode 100644
index 0000000..93beb63
--- /dev/null
+++ b/site2/docs/dev/design/raster_tragedy/_index.md
@@ -0,0 +1,204 @@
+
+---
+title: "The Raster Tragedy in Skia"
+linkTitle: "The Raster Tragedy in Skia"
+
+---
+
+
+This is an extension of [The Raster Tragedy at Low-Resolution Revisited](http://rastertragedy.com)
+as it applies to Skia. The Raster Tragedy describes a number of issues with typeface rasterization
+with a particular emphasis on proper hinting to overcome these issues. Since not all fonts
+are nicely hinted and sometimes hinting is not desired, there are additional hacks which may
+be applied. Generally, one wants to hint purely informational text laid out for a particular
+device, but not hint text which is art. Unless, of course, the hinting is part of the art like
+Shift_JIS art.
+
+
+
+The Gamma Hack
+--------------
+
+First, one should be aware of transfer functions (of which 'gamma' is an
+example). A good introduction can be had at [What Every Coder Should Know About
+Gamma](https://blog.johnnovak.net/2016/09/21/what-every-coder-should-know-about-gamma/).
+
+In Skia, all color sources are converted into the destination color space and the blending is done
+in the destination color space by applying the linear blend function. Skia does not convert into
+a linear space, apply the linear blend, and convert back to the encoded space. If the destination
+color space does not have a linear encoding this will lead to 'incorrect' blending. The idea is
+that there are essentially two kinds of users of Skia. First there are existing systems which
+are already using a non-linear encoding with a linear blend function. While the blend isn't
+correct, these users generally don't want anything to change due to expectations. Second there
+are those who want everything done correctly and they are willing to pay for a linearly encoded
+destination in which the linear blend function is correct.
+
+For bi-level glyph rendering a pixel is either covered or not, so there are no coverage blending
+issues.
+
+For regular full pixel partial coverage (anti-aliased) glyph rendering the user may or may not
+want correct linear blending. In most non-linear encodings, using the linear blend function
+tends to make black on white look slightly heavier, using the pixel grid as a kind of contrast
+and optical sizing enhancement. It does the opposite for white on black, often making such
+glyphs a bit under-covered. However, this fights the common issue of blooming where light on
+dark on many displays tends to appear thicker than dark on light. (The black not being fully
+black also contributes.) If the pixels are small enough and there is proper optical sizing and
+perhaps anti-aliased drop out control (these latter two achieved either manually with proper
+font selection or 'opsz', automatically, or through hinting) then correct linear blending tends
+to look great. Otherwise black on white text tends to (correctly) get really anemic looking at
+small sizes. So correct blending of glyph masks here should be left up to the user of Skia. If
+they're really sophisticated and already tackled these issues then they may want linear blending
+of the glyphs for best effect. Otherwise the glyphs should just keep looking like they used to
+look due to expectations.
+
+For subpixel partial coverage (subpixel anti-aliased) glyph masks linear blending in a
+linear encoding is more or less required to avoid color fringing effects. The intensity of
+the subpixels is being directly exploited so needs to be carefully controlled. The subpixels
+tend to alleviate the issues with no full coverage (though still problematic if blitting text
+in one of the display's primaries). One will still want optical sizing since the glyphs will
+still look somewhat too light when scaled down linearly.
+
+So, if subpixel anti-aliased glyph masks (and sometimes full pixel anti-aliased glyph masks)
+need a correct blit how are they to be used with non-linearly encoded destinations?
+
+One possible solution is to special case these blits. If blitting on the CPU it's often fast and
+close enough to take the square root of the source and destination values, do the linear blend
+function, then square the result (approximating the destination encoding as if its transfer
+function is square). Many GPUs have a mode where they can blend in sRGB, though unfortunately
+this generally applies to the whole framebuffer, not just individual draws. For various reasons,
+Skia has avoided special casing these blends.
+
+What Skia currently does is the gamma hack. When creating the glyph mask one usually knows
+the approximate color which is going to be drawn, the transfer function, and that a linear
+source-over blend is going to be used. The destination color is then guessed to be a contrasting
+color (if there isn't any contrast the drawing won't be able to be seen anyway) so assume that the
+destination color will be the perceptually opposite color in the destination color space. One can
+now determine the desired value by converting the perceptual source and guessed destination into
+a linear encoding, do the linear source-over blend, and convert to the destination encoding. The
+coverage is then adjusted so that the result of a linear source-over blend on the non-linear
+encoded values will be as close as possible to this desired value.
+
+This works, but makes many assumptions. The first is the guess at the destination. A perceptual
+middle gray could equally well (or poorly) contrast with black or white so the best guess
+is drawing it on top of itself. Subpixel anti-aliased glyph masks drawn with this guess will
+be drawn without any adjustment at all, leaving them color fringy. On macOS Skia tweaks the
+destination guess to reduce the correction when using bright sources. This helps reducing
+'blooming' issues with light on dark (aka dark mode) and better matches how CoreText seems
+to do blending. The second is that a src-over blend is assumed, but users generally aren't as
+discriminating of the results of other blends.
+
+The gamma hack works best with subpixel anti-aliasing since the adjustment can be made per-channel
+instead of full pixel. If this hack is applied to full pixel anti-aliased masks everything is
+essentially being done in the nearest gray instead of the nearest color (since there is only
+one channel through which to communicate), leading to poor results. Most users will not want
+the gamma hack applied to full pixel anti-aliased glyphs.
+
+Since the gamma hack is logically part of the blend, it must always be the very last adjustment
+made to the coverage mask before being used by the blitter. The inputs are the destination
+transfer function and the current color (in the destination color space). In Skia these come
+from the color space on the SkSurface and the color on the SkPaint.
+
+
+Optical Sizing Hack
+-------------------
+
+In metal type a type designer will draw out on paper the design for the faces of the final
+sorts. Often there would be different drawings for different target sizes. Sometimes these
+different sizes look quite different (like Display and Text faces of the same family). Then a
+punch cutter takes these drawings and creates a piece of metal called a punch which can stamp
+out these faces. The punch is used to create a negative in a softer piece of metal forming a
+strike. This strike is made the correct width and called a matrix. This matrix is used as a mold
+to cast individual sorts. The sorts are collected into a box called a type case. A typesetter
+would take sorts from a type case and set them into a form. The printer would then ink the
+sorts in the form and press the paper. (Note that the terms 'typeface' and 'font' aren't used
+in this description, there is a lot of disagreement on what they apply to.)
+
+Every step of this process is now automated in some way. Unfortunately, knowledge embedded in
+the manual process has not always been replicated in the automation. This can be for a wide
+variety of reasons, such as being overlooked or being difficult to emulate. One of these areas
+is the art of optical sizing and managing thin features.
+
+In general smaller type should be relatively heavier in weight than would be expected if taking
+a larger size and linearly scaling it down. The type designer will draw out the faces with this
+in mind, potentially with an eye toward how it would vary with size and with potential need
+for ink traps. The punch cutter would then cut the punches at a given size with this in mind,
+adjusting until the soot proofs looked good. There may even be slight adjustments to the matrix
+itself if something seemed off. The typesetter would often know which specific cases contained
+slightly heavier or lighter sorts. The printer would then adjust the ink and pressure to get
+a good looking print.
+
+Popular digital font formats didn't really support this until recently with the variable font
+'opsz' axis. The presence of an 'opsz' axis is like the type designer giving really good
+instructions about how the faces should look at various sizes. However, not all fonts have or
+will have a 'opsz' axis. Since we don't always have an 'opsz' what can be done to prevent small
+glyphs from looking all washed out?
+
+One way the type designer could influence the optical size is through hinting. Any manual
+hinting is done by someone looking at the result at small sizes. Tweaks are made until it
+'looks good'. This often unconsciously bakes in optical sizing. Even autohinters eventually
+end up emulating this, generally making the text more contrasty and somewhat heavier at small
+pixel sizes (this depends on the target pixel size not the nominal requested size).
+
+An alternate way the designer could provide optical sized fonts is using multiple font files
+for different optical sizes and expect the user to select the right one (like Display and
+Text variants). In theory the right one might also be selected automatically based on some
+criteria. Switching font files because of nominal size changes may seem drastic, but this is
+how the system font on macOS worked for a while.
+
+One automatic way to do optical sizing is to artificially embolden the outline itself at small
+nominal sizes. This is the approach taken by CoreText. This is a lot like the dreaded fake-bold,
+but doesn't have the issue of the automatic fake bolding being heavier than ultra bold, since
+this emboldening is applied uniformally based on requested nominal size.
+
+Another automatic way to do optical sizing is to over-cover all the edges when doing
+anti-aliasing. The pixels are a fixed physical size so affect small features more than large
+features. Skia currently has rudimentary support for this in its 'contrast hack' which is
+described more later.
+
+As a note on optical sizing, this is one place where the nominal or optical size of the font is
+treated differently from the final pixel size of the font. A SkCanvas may have a scale transform
+active. Any hinting will be done at the final pixel size (the font size mapped through the
+current transformation matrix), but the optical size is not affected by the transform since
+it's actually a parameter for the SkTypeface (and maybe the SkFont).
+
+
+The Contrast Hack
+-----------------
+
+Consider the example of [a pixel wide stroke at half-pixel
+boundaries](http://rastertragedy.com/RTRCh3.htm#Sec1). As stated in section 3.1.3 "if we were
+to choose the stroke positions to render the most faithful proportions and advance width, we
+may have to compromise the rendering contrast." If the stroke lands on a pixel boundary all
+is well. If the stoke lands at a half pixel boundary and correct linear blending is used then
+the same number of photons are reaching the eye, but the reduction in photons is spread out
+over twice the area. If the pixels were small enough then this wouldn't be an issue. Back of
+the envelope suggests an 8K 20inch desktop monitor or ~400ppi being the minimum. Note that RGB
+subpixel anti-aliasing brings a 100dpi display up to 300dpi, which is close, but still a bit
+short. Exploiting the RGB subpixels also doesn't really increase the resolution as much when
+getting close to the RGB primaries for the fill color.
+
+One way to try to compensate for this is to cover some of these partially covered pixels more
+until it visually looks better. Note that this depends on a lot of factors like the pixel density
+of the display, the visual acuity of the user, the distance of the user from the display, and the
+user's sensitivity to the potential variations in stem darkness which may result. Automatically
+taking all these factors into account would be quite difficult. The correct function is generally
+determined by having the user look at the result of applying various amounts of extra coverage
+and having them to pick a setting that looks the least bad to them.
+
+This specific form of over-covering is a form of drop out control for anti-aliasing and could
+be implemented in a similar way, detecting when a stem comes on in one pixel and goes out in
+the next and mark that for additional coverage. At raster time a cruder approximation could be
+made by doing a pass in each of the horizontal and vertical directions and finding runs of more
+than one non-fully-covered pixel and increasing their coverage.
+
+If instead of doing these computationally expensive passes all coverage is boosted then in
+addition to the smeared stems the entire outside edge of the glyph will also be bolded. Making
+these outside edges heavier is a crude approximation of outsetting the initial path in a
+rather complicated way and amounts to an optical sizing tweak. Just as hinting can be used to
+approximate optical sizing if the user's perception of the pixel sizes is known in advance,
+this is a pixel level tweak tied to a specific user and display combination.
+
+Much like the gamma hack can be modified to reduce the correction for light on dark to
+fight blooming, the contrast hack can be reduced when the color being drawn is known to be
+light. Generally the contrast correction goes to zero as one approaches white.
+
diff --git a/site2/docs/dev/flutter/_index.md b/site2/docs/dev/flutter/_index.md
new file mode 100644
index 0000000..0f08dab
--- /dev/null
+++ b/site2/docs/dev/flutter/_index.md
@@ -0,0 +1,29 @@
+
+---
+title: "Skia in Flutter & Fuchsia"
+linkTitle: "Skia in Flutter & Fuchsia"
+
+---
+
+
+Skia is used by both [Flutter](https://flutter.io/) and [Fuchsia](https://fuchsia.googlesource.com/docs/+/master/README.md).
+
+Fuchsia has a [roller](https://fuchsia-roll.skia.org/) that will continuously roll latest Skia into that project. Fuchsia uses an XML [manifest](https://fuchsia.googlesource.com/manifest/+/master/userspace) to specify the Skia revision (as well as other third party libraries).
+
+Flutter does not (yet) have a roller, so developers must manually perform rolls. Flutter uses [DEPS](https://github.com/flutter/engine/blob/master/DEPS) to specify third party dependencies.
+
+
+Although each project is (almost always) building at a different revision of Skia, Fuchsia itself always builds the latest revision of Flutter as one of its components. Thus, the versions of Skia being used by Flutter and Fuchsia must be "source compatible" -- Flutter must be capable of compiling against either revision without any change to Flutter itself.
+
+Making API Changes
+------------------
+
+If you need to make a breaking API change, the basic approach is:
+
+* Add new code to Skia, leaving the old code in place.
+* Deprecate the old code path so that it must be enabled with a flag such as 'SK_SUPPORT_LEGACY_XXX'.
+* Add that same flag to [flutter\_defines.gni](https://skia.googlesource.com/skia/+/master/gn/flutter_defines.gni) in Skia.
+  * Both Flutter and Fuchsia build Skia with a GN argument that enables all the defines listed in that file.
+* Land the Skia change, and test the new API in both Flutter and Fuchsia.
+* Remove the flag and code when the legacy code path is no longer in use.
+
diff --git a/site2/docs/dev/gardening/_index.md b/site2/docs/dev/gardening/_index.md
new file mode 100644
index 0000000..1af2631
--- /dev/null
+++ b/site2/docs/dev/gardening/_index.md
@@ -0,0 +1,191 @@
+
+---
+title: "Skia Gardener Documentation"
+linkTitle: "Skia Gardener Documentation"
+
+weight: 8
+
+---
+
+
+### Contents ###
+
+*   [What does a Skia Gardener do?](#what_is_a_skia_gardener)
+    +   [Skia tree](#skia_tree)
+    +   [AutoRollers](#autorollers)
+    +   [Gold and Perf](#gold_and_perf)
+    +   [Documentation](#skia_gardener_doc)
+*   [View current and upcoming rotations](#view_current_upcoming_rotations)
+*   [How to swap rotation shifts](#how_to_swap)
+*   [Tips for Skia Gardeners](#tips)
+    +   [When to file bugs](#when_to_file_bugs)
+    +   [How to close or re-open the tree](#how_close_tree)
+    +   [How to revert a CL](#how_to_revert)
+    +   [What to do if DEPS roll fails to land](#deps_roll_failures)
+    +   [How to rebaseline](#how_to_rebaseline)
+
+
+<a name="what_is_a_skia_gardener"></a>
+What does a Skia Gardener do?
+-----------------------------
+
+A Skia Gardener keeps an eye on the tree, DEPS rolls, Gold tool, the Perf tool, and triages Chrome bugs.
+
+Below is a brief summary of what the gardener does for each task:
+
+<a name="skia_tree"></a>
+### Skia tree
+* Understand the [testing infrastructure](https://skia.org/dev/testing/automated_testing).
+* Start watching the [status page](https://status.skia.org) for bot breakages.
+* Track down people responsible for breakages and revert broken changes if there is no easy fix. You can use [blamer](#blamer) to help track down such changes.
+* Close and open the [tree](http://tree-status.skia.org).
+* Keep the builder comments on the [status page](https://status.skia.org) up to date.
+* File or follow up with [BreakingTheBuildbots bugs](https://bugs.chromium.org/p/skia/issues/list?q=label:BreakingTheBuildbots). See the tip on [when to file bugs](#when_to_file_bugs).
+* Read and update the [Ongoing Issues section](https://docs.google.com/document/d/1y2jUf4vXI0fwhu2TiCLVIfWC1JOxFcHXGw39y7i-y_I/edit#heading=h.tpualuc3p7z0) in the handoff doc.
+* (Optional) Document significant events that occurred during your shift in the [Weekly
+  Handoff Notes section](https://docs.google.com/document/d/1y2jUf4vXI0fwhu2TiCLVIfWC1JOxFcHXGw39y7i-y_I/edit#heading=h.y49irwbutzr) in the handoff doc.
+
+<a name="triage"></a>
+### Triage
+You should triage Chromium and Skia bugs that show up under "Untriaged Bugs" on the [status page](https://status.skia.org).
+The Android Gardener will triage the untriaged Android Bugs.
+For a more detailed view of bugs see [Skia Bugs Central](https://bugs-central.skia.org/).
+
+<a name="blamer"></a>
+### Blamer
+If you have Go installed, a command-line tool is available to search through
+git history and do text searches on the full patch text and the commit
+message. To install blamer run:
+
+    go get go.skia.org/infra/blamer/go/blamer
+
+Then run blamer from within a Skia checkout. For example, to search if the
+string "SkDevice" has appeared in the last 10 commits:
+
+    $ $GOPATH/bin/blamer --match SkDevice --num 10
+
+    commit ea70c4bb22394c8dcc29a369d3422a2b8f3b3e80
+    Author: robertphillips <robertphillips@google.com>
+    Date:   Wed Jul 20 08:54:31 2016 -0700
+
+        Remove SkDevice::accessRenderTarget virtual
+        GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2167723002
+
+        Review-Url: https://codereview.chromium.org/2167723002
+
+<a name="autorollers"></a>
+### Autorollers
+* Ensure that all AutoRollers listed on the [status page](https://status.skia.org) are successfully landing.
+
+<a name="gold_and_perf"></a>
+### Gold and Perf
+* Pay attention for new [Perf](https://perf.skia.org/) and [Gold](https://gold.skia.org/) alerts (by clicking on the bell at the top right of the [status page](https://status.skia.org)).
+* The gardener's duty here is to make sure that when developers introduce new images or new perf regressions, that they are aware of what happened, and they use these tools to take appropriate action.
+
+<a name="skia_gardener_doc"></a>
+### Documentation
+* Improve/update this documentation page for future gardeners, especially the [Tips section](#tips).
+
+In general, gardeners should have a strong bias towards actions that keep the tree green and then open; if a simple revert can fix the problem, the gardener <b>should revert first and ask questions later</b>.
+
+
+<a name="view_current_upcoming_rotations"></a>
+View current and upcoming rotations
+-----------------------------------
+
+The list of Skia Gardeners is specified [here](https://rotations.corp.google.com/rotation/4699606003744768).
+The gardeners widget on the [status page](https://status.skia.org) also displays the current gardeners.
+
+
+<a name="how_to_swap"></a>
+How to swap rotation shifts
+---------------------------
+
+If you need to swap shifts with someone (because you are out sick or on vacation), please get approval from the person you want to swap with and directly make the swap via the [rotations page](https://rotations.corp.google.com/rotation/4699606003744768).
+
+
+<a name="tips"></a>
+Tips for Skia Gardeners
+-----------------
+
+<a name="when_to_file_bugs"></a>
+### When to file bugs
+
+Pay close attention to the "Failures" view in the [status page](https://status.skia.org).
+Look at all existing [BreakingTheBuildbots bugs](https://bug.skia.org/?q=label:BreakingTheBuildbots). If the list is kept up to date then it should accurately represent everything that is causing failures. If it does not, then please file/update bugs accordingly.
+
+
+<a name="how_close_tree"></a>
+### How to close or re-open the tree
+
+1. Go to [tree-status.skia.org](https://tree-status.skia.org).
+2. Change the status.
+ *  To close the tree, include the word "closed" in the status.
+ * To open the tree, include the word "open" in the status.
+ * To caution the tree, include the word "caution" in the status.
+
+
+<a name="how_to_submit_when_tree_closed"></a>
+### How to submit when the tree is closed
+
+* Submit manually using the "git cl land" with the --bypass-hooks flag.
+* Add "No-Tree-Checks: true" to your CL description and use the CQ as usual.
+
+
+<a name="how_to_revert"></a>
+### How to revert a CL
+
+See the revert documentation [here](https://skia.org/dev/contrib/revert).
+
+
+<a name="deps_roll_failures"></a>
+### What to do if DEPS roll fails to land
+
+A common cause of DEPS roll failures are layout tests. Find the offending Skia CL by examining the commit hash range in the DEPS roll and revert (or talk to the commit author if they are available). If you do revert then keep an eye on the next DEPS roll to make sure it succeeds.
+
+If a Skia CL changes layout tests, but the new images look good, the tests need to be rebaselined. See [Rebaseline Layout Tests](#how_to_rebaseline).
+
+<a name="how_to_rebaseline"></a>
+### Rebaseline Layout Tests (i.e., add suppressions)
+
+* First create a Chromium bug:
+  * goto [crbug.com](https://crbug.com)
+  * Make sure you're logged in with your Chromium credentials
+  * Click “New Issue”
+  * Summary: “Skia image rebaseline”
+  * Description:
+      * DEPS roll #,
+      * Helpful message about what went wrong (e.g., “Changes to how lighting is scaled in Skia r#### changed the following images:”)
+      * Layout tests affected
+      * You should copy the list of affected from stdio of the failing bot
+  * Status: Assigned
+  * Owner: yourself
+  * cc: reed@, bsalomon@, robertphillips@ & developer responsible for changes
+  * Labels: OS-All & Cr-Blink-LayoutTests
+  * If it is filter related, cc senorblanco@
+
+* (Dispreferred but faster) Edit [skia/skia_test_expectations.txt](https://chromium.googlesource.com/chromium/src/+/master/skia/skia_test_expectations.txt)
+  * Add # comment about what has changed (I usually paraphrase the crbug text)
+  * Add line(s) like the following after the comment:
+      * crbug.com/<bug#youjustcreated> foo/bar/test-name.html [ ImageOnlyFailure ]
+  * Note: this change is usually done in the DEPS roll patch itself
+
+* (Preferred but slower) Make a separate Blink patch by editing LayoutTests/TestExpectations
+  * Add # comment about what has changed (I usually paraphrase the crbug text)
+  * Add line(s) like the following after the comment:
+      * crbug.com/<bug#youjustcreated> foo/bar/test-name.html [ Skip ]  # needs rebaseline
+  * Commit the patch you created and wait until it lands and rolls into Chrome
+
+* Retry the DEPS roll (for the 1st/dispreferred option this usually means just retrying the layout bots)
+* Make a Blink patch by editing LayoutTests/TestExpectations
+  * Add # comment about what has changed
+  * Add line(s) like the following after the comment:
+      * crbug.com/<bug#youjustcreated> foo/bar/test-name.html [ Skip ]  # needs rebaseline
+        * (if you took the second option above you can just edit the existing line(s))
+
+* If you took the first/dispreferred option above:
+  * Wait for the Blink patch to roll into Chrome
+  * Create a Chrome patch that removes your suppressions from skia/skia_test_expectations.txt
+
+
+
diff --git a/site2/docs/dev/gardening/android.md b/site2/docs/dev/gardening/android.md
new file mode 100644
index 0000000..a6985ba
--- /dev/null
+++ b/site2/docs/dev/gardening/android.md
@@ -0,0 +1,70 @@
+
+---
+title: "Android Gardener Documentation"
+linkTitle: "Android Gardener Documentation"
+
+---
+
+
+### Contents ###
+
+*   [What does a Android Gardener do?](#what_is_a_android_gardener)
+*   [Android Autorollers](#autoroller_doc)
+*   [View current and upcoming rotations](#view_current_upcoming_rotations)
+*   [How to swap rotation shifts](#how_to_swap)
+
+
+<a name="what_is_a_android_gardener"></a>
+What does a Android Gardener do?
+--------------------------------
+
+The Android Gardener has two primary jobs:
+
+1) Monitor and approve the semi-autonomous [git merges](https://googleplex-android-review.git.corp.google.com/#/q/owner:31977622648%2540project.gserviceaccount.com+status:open) from Skia's repository into the Android source tree. See autoroller documentation <a href="#autoroller_doc">here</a> for details on how to interact with it.
+
+2) Stay on top of incoming Android-related bugs in both the [Skia](https://bugs.chromium.org/p/skia/issues/list?can=2&q=OpSys%3DAndroid&sort=-id&colspec=ID+Type+Status+Priority+Owner+Summary&cells=tiles) and [Android](https://buganizer.corp.google.com/issues?q=assignee:skia-android-triage%20status:open) bug trackers.  For Skia bugs, this means triaging and assigning all Android bugs that are currently unassigned.  For Android, this means following the [Android guidelines](go/android-buganizer) to verifying that all Skia bugs are TL-triaged (if not reach out to djsollen@).
+
+The Android Gardener's job is NOT to address issues in Perf and Gold. You'll get your chance when you are the general Skia Gardener.
+
+
+<a name="autoroller_doc"></a>
+Android Autorollers
+-------------------
+
+The Android autoroller into the master branch runs on [https://android-master-roll.skia.org](android-master-roll.skia.org) and is accessible only to Googlers.<br/>
+The autoroller's status is displayed on Skia's [status page](https://status.skia.org/).
+
+You can send the autoroller into dry run mode via the UI. The uploaded change will not autosubmit when it is in dry run mode.
+
+You can also stop the autoroller via the UI. This is useful in cases where a failure needs to be investigated and you do not want to waste TH resources by running unnecessary tests.
+
+If the autoroller displays an error in the UI then look for more detail in it's [cloud logs](https://pantheon.corp.google.com/logs/viewer?project=google.com:skia-buildbots&resource=logging_log%2Fname%2Fandroid-master-autoroll&logName=projects%2Fgoogle.com:skia-buildbots%2Flogs%2Fautoroll).
+
+If you need any more information about the autoroller please look at [skia:5538](https://bugs.chromium.org/p/skia/issues/detail?id=5538) or ask rmistry@ / skiabot@.
+
+We also have autorollers into release branches (also restricted only to Googlers):
+
+* [https://android-o-roll.skia.org](https://android-o-roll.skia.org) ([cloud logs](https://pantheon.corp.google.com/logs/viewer?project=google.com:skia-buildbots&resource=logging_log%2Fname%2Fandroid-o-autoroll&logName=projects%2Fgoogle.com:skia-buildbots%2Flogs%2Fautoroll)).
+
+Changes created by these rollers need to be manually approved.<br/>
+The changes created by the release rollers:
+
+* Include all authors of merged changes so that they can watch the roll.
+* Extracts all buganizer bugs of the form 'BUG=b/123' or 'Bug: b/456' and creates a single line in the merge change 'Bug: 123, 456'.
+* Collects all 'Test: ' lines and carries them over to the merge change.
+
+
+<a name="view_current_upcoming_rotations"></a>
+View current and upcoming rotations
+-----------------------------------
+
+The list of Android Gardeners is specified [here](https://rotations.corp.google.com/rotation/5296436538245120).
+The gardeners widget on the [status page](https://status.skia.org) also displays the current gardeners.
+
+
+<a name="how_to_swap"></a>
+How to swap rotation shifts
+--------------------------
+
+If you need to swap shifts with someone (because you are out sick or on vacation), please get approval from the person you want to swap with and directly make the swap via the [rotations page](https://rotations.corp.google.com/rotation/5296436538245120).
+
diff --git a/site2/docs/dev/gardening/gpu.md b/site2/docs/dev/gardening/gpu.md
new file mode 100644
index 0000000..d858653
--- /dev/null
+++ b/site2/docs/dev/gardening/gpu.md
@@ -0,0 +1,65 @@
+
+---
+title: "GPU Gardener Documentation"
+linkTitle: "GPU Gardener Documentation"
+
+---
+
+
+### Contents ###
+
+*   [What does a GPU Gardener do?](#what_is_a_gpu_gardener)
+*   [Tracking GPU Gardener Work](#tracking)
+*   [View current and upcoming rotations](#view_current_upcoming_rotations)
+*   [How to swap rotation shifts](#how_to_swap)
+*   [Tips for GPU Gardeners](#tips)
+
+
+<a name="what_is_a_gpu_gardener"></a>
+What does a GPU Gardener do?
+----------------------------
+
+The GPU Gardener has three main jobs:
+
+1) Stay on top of incoming GPU-related bugs from clients in various bug trackers. This means triaging and assigning bugs that have a clear owner and investigating and possibly fixing bugs that don't.
+
+
+2) Improve the reliability of the GPU bots. This includes dealing with flaky images, crashing bots, etc. We have a never ending set of machine or driver specific issues to deal with. We often brush them under the rug so that we have time for the "real work." When you're gardener this is "real work."
+
+
+3) Improve our tooling. This includes writing new tools and improving existing test tools. Expected results are faster bot run times, more accurate testing, faster testing, surfacing new useful data, and improving debuggability.
+
+
+The GPU Gardener should always prioritize dealing with incoming bugs. The balance of a gardener's time should be spent divided as seen fit between 2) and 3). It is expected that as much as possible a gardener puts normal work on pause and focuses on gardener tasks for the full week. It is ok (and encouraged) to take a deep dive on one particular facet of the gardener duties and drive it as far as possible during gardener week (while staying on top of incoming bugs).
+
+Note that the GPU Gardener's job is NOT to spend an abnormal amount of time triaging images, filing bugs for failing bots, or shepherding DEPS rolls. You'll get your chance when you are the general Skia Gardener.
+
+<a name="tracking"></a>
+Tracking GPU Gardener Work
+--------------------------
+Outside of bug reports, a GPU Gardener should track their progress so that a future gardener can pick up any batons left shy of the finish line at week's end.
+
+Also, whenever a gardener figures out how to accomplish a gardenly task (e.g. run a set of Chromium tests that aren't well documented or a cool OpenGL trick used to debug a gnarly issue) the tips section of this doc should be updated to assist future gardeners.
+
+
+<a name="view_current_upcoming_rotations"></a>
+View current and upcoming rotations
+-----------------------------------
+
+The list of GPU Gardeners is specified [here](https://rotations.corp.google.com/rotation/6176639586140160).
+The gardeners widget on the [status page](https://status.skia.org) also displays the current gardeners.
+
+
+<a name="how_to_swap"></a>
+How to swap rotation shifts
+---------------------------
+
+If you need to swap shifts with someone (because you are out sick or on vacation), please get approval from the person you want to swap with and directly make the swap via the [rotations page](https://rotations.corp.google.com/rotation/6176639586140160).
+
+
+<a name="tips"></a>
+Tips for GPU Gardeners
+----------------------
+
+Please see [this](https://docs.google.com/a/google.com/document/d/1Q1A5T5js4MdqvD0EKjCgNbUBJfRBMPKR3OZAkc-2Tvc/edit?usp=sharing) doc.
+
diff --git a/site2/docs/dev/gardening/infra.md b/site2/docs/dev/gardening/infra.md
new file mode 100644
index 0000000..7ded610
--- /dev/null
+++ b/site2/docs/dev/gardening/infra.md
@@ -0,0 +1,11 @@
+
+---
+title: "Infra Gardener Documentation"
+linkTitle: "Infra Gardener Documentation"
+
+---
+
+
+The Infra Gardener handles problems with Skia's build and test infrastructure.
+Documentation for Infra Gardeners is found at [go/skia-infra-gardener](http://go/skia-infra-gardener) (Googler's only).
+
diff --git a/site2/docs/dev/internal/_index.md b/site2/docs/dev/internal/_index.md
new file mode 100644
index 0000000..a0da7c8
--- /dev/null
+++ b/site2/docs/dev/internal/_index.md
@@ -0,0 +1,42 @@
+---
+title: 'Internal Links'
+linkTitle: 'Internal Links'
+---
+
+Index of links to resources that are internal to the Google/Skia core team, for
+easy reference.
+
+## Skia team information
+
+- [Granting access to Skia](https://sites.google.com/a/google.com/skia/key-resources/access)
+- [Project communications](https://sites.google.com/a/google.com/skia/key-resources)
+
+## Skia project information
+
+- [Milestones and schedule](https://sites.google.com/a/google.com/skia/milestones)
+- [Status](https://sites.google.com/a/google.com/skia/status) from weekly,
+  monthly updates and OKRs
+- [Skia branch process](https://docs.google.com/a/google.com/document/d/1Xn24lTMlmUgdP8bp-iHOeGKAOp8L5uCxg12lw49Jlpg/edit?usp=sharing)
+- [Design documents](https://sites.google.com/a/google.com/skia/design-documents)
+
+## Infrastructure related
+
+- [iOS tools](https://sites.google.com/a/google.com/skia/key-resources/ios-provisioning)
+  for machine setup and provisioning
+- [SKP Playback](https://docs.google.com/a/google.com/document/d/1oJpuY8XKc212RsfUm6oEH2tp26Veb-Gez3clBuqapE4/edit?usp=sharing)
+  for downloading buildbot SKPs
+
+## Chrome related
+
+- [Development on a Chrome branch](https://sites.google.com/a/google.com/skia/development-on-a-chrome-branch)
+- [Cherrypick instructions](https://sites.google.com/a/google.com/skia/development-on-a-chrome-branch#TOC-How-to-cherrypick-a-Skia-fix-into-a-Chrome-branch)
+
+## Android related
+
+- Skia on Android
+  [development guide](https://sites.google.com/a/google.com/skia/android)
+
+## Google3 related
+
+- [Google3-Autoroller](https://sites.google.com/a/google.com/skia-infrastructure/docs/google3-autoroller)
+  -- How to handle failures and how to test CLs.
diff --git a/site2/docs/dev/present/_index.md b/site2/docs/dev/present/_index.md
new file mode 100644
index 0000000..152b3e9
--- /dev/null
+++ b/site2/docs/dev/present/_index.md
@@ -0,0 +1,12 @@
+
+---
+title: "Presentations"
+linkTitle: "Presentations"
+
+weight: 5
+
+---
+
+
+Resources providing technical overview of various aspects of the Skia library
+
diff --git a/site2/docs/dev/present/pathops.md b/site2/docs/dev/present/pathops.md
new file mode 100644
index 0000000..70279f8
--- /dev/null
+++ b/site2/docs/dev/present/pathops.md
@@ -0,0 +1,33 @@
+
+---
+title: "Path Ops"
+linkTitle: "Path Ops"
+
+---
+
+
+View the PathOps presentations with speaker notes enabled for full content. 
+
+2013 Path Ops Presentation
+------------
+<iframe
+src="https://docs.google.com/presentation/d/1iEjbQV4o40hoooB9DiAHjH9P9Q5CrVUUnbYdQtQB6_A/embed?start=false&loop=false&delayms=3000"
+frameborder="0" width="480" height="299" allowfullscreen="true"
+mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
+
+2014 Update
+------------
+<iframe
+src="https://docs.google.com/presentation/d/1NbmG5W6VW9h5HtjpCVLx4h6SXW0qW7HIwmSfiwzFbrI/embed?start=false&loop=false&delayms=3000"
+frameborder="0" width="480" height="299" allowfullscreen="true"
+mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
+
+2015 Update
+------------
+<iframe
+src="https://docs.google.com/presentation/d/1PoZdIx4DqdIvs7ybv-L3EvtxQE2qXuzeOZpSkFJjfhg/embed?start=false&loop=false&delayms=3000"
+frameborder="0" width="480" height="299" allowfullscreen="true"
+mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
+
+## [Path Ops Inverse Fill Illustration](https://drive.google.com/file/d/0BwoLUwz9PYkHLWpsaXd0UDdaN00/view?usp=sharing)
+
diff --git a/site2/docs/dev/testing/_index.md b/site2/docs/dev/testing/_index.md
new file mode 100644
index 0000000..ca10247
--- /dev/null
+++ b/site2/docs/dev/testing/_index.md
@@ -0,0 +1,23 @@
+
+---
+title: "Testing"
+linkTitle: "Testing"
+
+weight: 3
+
+---
+
+
+Skia relies heavily on our suite of unit and GM tests, which are served by our
+DM test tool, for correctness testing. Tests are executed by our trybots, for
+every commit, across most of our supported platforms and configurations.
+Skia [Gold](https://gold.skia.org) is a web interface for triaging these results.
+
+We also have a robust set of performance tests, served by the nanobench tool and
+accessible via the Skia [Perf](https://perf.skia.org) web interface.
+
+Cluster Telemetry is a powerful framework that helps us capture and benchmark
+SKP files, a binary format for draw commands, across up to one million websites.
+
+See the individual subpages for more details on our various test tools.
+
diff --git a/site2/docs/dev/testing/automated_testing.md b/site2/docs/dev/testing/automated_testing.md
new file mode 100644
index 0000000..48f687c
--- /dev/null
+++ b/site2/docs/dev/testing/automated_testing.md
@@ -0,0 +1,193 @@
+
+---
+title: "Skia Automated Testing"
+linkTitle: "Skia Automated Testing"
+
+---
+
+
+Overview
+--------
+
+Skia uses [Swarming](https://github.com/luci/luci-py/blob/master/appengine/swarming/doc/Design.md)
+to do the heavy lifting for our automated testing. It farms out tasks, which may
+consist of compiling code, running tests, or any number of other things, to our
+bots, which are virtual or real machines living in our local lab, Chrome Infra's
+lab, or in GCE.
+
+The [Skia Task Scheduler](http://go/skia-task-scheduler) determines what tasks
+should run on what bots at what time. See the link for a detailed explanation of
+how relative task priorities are derived. A *task* corresponds to a single
+Swarming task. A *job* is composed of a directed acyclic graph of one or more
+*tasks*. The job is complete when all of its component tasks have succeeded
+or is considered a failure when any of its component tasks fails. The scheduler
+may automatically retry tasks within its set limits. Jobs are not retried.
+Multiple jobs may share the same task, for example, tests on two different
+Android devices which use the same compiled code.
+
+Each Skia repository has an `infra/bots/tasks.json` file which defines the jobs
+and tasks for the repo. Most jobs will run at every commit, but it is possible
+to specify nightly and weekly jobs as well. For convenience, most repos also
+have a `gen_tasks.go` which will generate `tasks.json`. You will need to
+[install Go](https://golang.org/doc/install). From the repository root:
+
+	$ go run infra/bots/gen_tasks.go
+
+It is necessary to run `gen_tasks.go` every time it is changed or every time an
+[asset](https://skia.googlesource.com/skia/+/master/infra/bots/assets/README.md)
+has changed. There is also a test mode which simply verifies that the `tasks.json`
+file is up to date:
+
+	$ go run infra/bots/gen_tasks.go --test
+
+
+
+Try Jobs
+--------
+
+Skia's trybots allow testing and verification of changes before they land in the
+repo. You need to have permission to trigger try jobs; if you need permission,
+ask a committer. After uploading your CL to [Gerrit](https://skia-review.googlesource.com/),
+you may trigger a try job for any job listed in `tasks.json`, either via the
+Gerrit UI, using `git cl try`, eg.
+
+    git cl try -B skia.primary -b Some-Tryjob-Name
+
+or using `bin/try`, a small wrapper for `git cl try` which helps to choose try jobs.
+From a Skia checkout:
+
+    bin/try --list
+
+You can also search using regular expressions:
+
+    bin/try "Test.*GTX660.*Release"
+
+
+Status View
+------------
+
+The status view shows a table with tasks, grouped by test type and platform,
+on the X-axis and commits on the Y-axis.  The cells are colored according to
+the status of the task for each commit:
+
+* green: success
+* orange: failure
+* purple: mishap (infrastructure issue)
+* black border, no fill: task in progress
+* blank: no task has started yet for a given revision
+
+Commits are listed by author, and the branch on which the commit was made is
+shown on the very left. A purple result will override an orange result.
+
+For more detail, you can click on an individual cell to get a summary of the
+task.  You can also click one of the white bars at the top of each column to see
+a summary of recent tasks with the same name.
+
+The status page has several filters which can be used to show only a subset of
+task specs:
+
+* Interesting: Task specs which have both successes and failures within the
+  visible commit window.
+* Failures: Task specs which have failures within the visible commit window.
+* Comments: Task specs which have comments.
+* Failing w/o comment: task specs which have failures within the visible commit
+  window but have no comments.
+* All: Display all tasks.
+* Search: Enter a search string. Substrings and regular expressions may be
+  used, per the Javascript String Match() rules:
+  http://www.w3schools.com/jsref/jsref_match.asp
+
+<a name="adding-new-jobs"></a>
+Adding new jobs
+---------------
+
+If you would like to add jobs to build or test new configurations, please file a
+[New Bot Request][new bot request].
+
+If you know that the new jobs will need new hardware or you aren't sure which
+existing bots should run the new jobs, assign to jcgregorio. Once the Infra team
+has allocated the hardware, we will assign back to you to complete the process.
+
+Generally it's possible to copy an existing job and make changes to accomplish
+what you want. You will need to add the new job to
+[infra/bots/jobs.json][jobs json]. In some cases, you will need to make changes
+to recipes:
+
+* If there are new GN flags or compiler options:
+  [infra/bots/recipe_modules/build][build recipe module], probably default.py.
+* If there are modifications to dm flags: [infra/bots/recipes/test.py][test py]
+* If there are modifications to nanobench flags:
+  [infra/bots/recipes/perf.py][perf py]
+
+After modifying any of the above files, run `make train` in the infra/bots
+directory to update generated files. Upload the CL, then run `git cl try -B
+skia.primary -b <job name>` to run the new job. (After commit, the new job will
+appear in the PolyGerrit UI after the next successful run of the
+Housekeeper-Nightly-UpdateMetaConfig task.)
+
+[new bot request]:
+    https://bugs.chromium.org/p/skia/issues/entry?template=New+Bot+Request
+[jobs json]: https://skia.googlesource.com/skia/+/master/infra/bots/jobs.json
+[build recipe module]:
+    https://skia.googlesource.com/skia/+/refs/heads/master/infra/bots/recipe_modules/build/
+[test py]:
+    https://skia.googlesource.com/skia/+/master/infra/bots/recipes/test.py
+[perf py]:
+    https://skia.googlesource.com/skia/+/master/infra/bots/recipes/perf.py
+
+
+Detail on Skia Tasks
+--------------------
+
+[infra/bots/gen_tasks.go][gen_tasks] reads config files:
+
+* [infra/bots/jobs.json][jobs json]
+* [infra/bots/cfg.json][cfg json]
+* [infra/bots/recipe_modules/builder_name_schema/builder_name_schema.json][builder_name_schema]
+
+Based on each job name in jobs.json, gen_tasks decides which tasks to generate (process
+function). Various helper functions return task name of the direct dependencies of the job.
+
+In gen_tasks, tasks are specified with a TaskSpec. A TaskSpec specifies how to generate and trigger
+a Swarming task.
+
+Most Skia tasks run a recipe with Kitchen. The arguments to the kitchenTask function specify the
+most common parameters for a TaskSpec that will run a recipe. More info on recipes at
+[infra/bots/recipes/README.md][recipes README] and
+[infra/bots/recipe_modules/README.md][recipe_modules README].
+
+The Swarming task is generated based on several parameters of the TaskSpec:
+
+* Isolate: specifies the isolate file. The isolate file specifies the files from the repo to place
+  on the bot before running the task. (For non-Kitchen tasks, the isolate also specifies the command
+  to run.) [More info][isolate user guide].
+* Command: the command to run, if not specified in the Isolate. (Generally this is a boilerplate
+  Kitchen command that runs a recipe; see below.)
+* CipdPackages: specifies the IDs of CIPD packages that will be placed on the bot before running the
+  task. See infra/bots/assets/README.md for more info.
+* Dependencies: specifies the names of other tasks that this task depends upon. The outputs of those
+  tasks will be placed on the bot before running this task.
+* Dimensions: specifies what kind of bot should run this task. Ask Infra team for how to set this.
+* ExecutionTimeout: total time the task is allowed to run before it is killed.
+* IoTimeout: amount of time the task can run without printing something to stdout/stderr before it
+  is killed.
+* Expiration: Mostly ignored. If the task happens to be scheduled when there are no bots that can
+  run it, it will remain pending for this long before being canceled.
+
+If you need to do something more complicated, or if you are not sure how to add
+and configure the new jobs, please ask for help from borenet, benjaminwagner, or
+mtklein.
+
+[gen_tasks]:
+	https://skia.googlesource.com/skia/+/master/infra/bots/gen_tasks.go
+[cfg json]:
+	https://skia.googlesource.com/skia/+/master/infra/bots/cfg.json
+[builder_name_schema]:
+	https://skia.googlesource.com/skia/+/master/infra/bots/recipe_modules/builder_name_schema/builder_name_schema.json
+[recipes README]:
+    https://skia.googlesource.com/skia/+/master/infra/bots/recipes/README.md
+[recipe_modules README]:
+    https://skia.googlesource.com/skia/+/master/infra/bots/recipe_modules/README.md
+[isolate user guide]:
+    https://chromium.googlesource.com/infra/luci/luci-py/+/master/appengine/isolate/doc/client/Isolate-User-Guide.md
+
diff --git a/site2/docs/dev/testing/download.md b/site2/docs/dev/testing/download.md
new file mode 100644
index 0000000..45f8e21
--- /dev/null
+++ b/site2/docs/dev/testing/download.md
@@ -0,0 +1,38 @@
+
+---
+title: "Downloading Isolates"
+linkTitle: "Downloading Isolates"
+
+---
+
+
+The intermediate and final build products from running tests are all stored in
+[Isolate](https://github.com/luci/luci-py/blob/master/appengine/isolate/doc/Design.md),
+and can be downloaded to the desktop for inspection and debugging.
+
+First install the client:
+
+     git clone https://github.com/luci/client-py.git
+
+Add the checkout location to your $PATH.
+
+To download the isolated files for a test first visit
+the build status page and find the "isolated output" link:
+
+<img src="Status.png" style="margin-left:30px" width=576 height=271 >
+
+
+Follow that link to find the hash of the isolated outputs:
+
+
+<img src="Isolate.png" style="margin-left:30px" width=451 height=301 >
+
+Then run `isolateserver.py` with --isolated set to that hash:
+
+    $ isolateserver.py \
+      download \
+      --isolate-server=https://isolateserver.appspot.com \
+      --isolated=5b85b7c382ee2a34530e33c7db20a07515ff9481 \
+      --target=./download/
+
+
diff --git a/site2/docs/dev/testing/fonts.md b/site2/docs/dev/testing/fonts.md
new file mode 100644
index 0000000..678bae0
--- /dev/null
+++ b/site2/docs/dev/testing/fonts.md
@@ -0,0 +1,40 @@
+
+---
+title: "Fonts and GM Tests"
+linkTitle: "Fonts and GM Tests"
+
+---
+
+
+Overview
+--------
+
+Each test in the gm directory draws a reference image. Their primary purpose is
+to detect when images change unexpectedly, indicating that a rendering bug has
+been introduced.
+
+The gm tests have a secondary purpose: they detect when rendering is different
+across platforms and configurations.
+
+GM font selection
+-----------------
+
+Each gm specifies the typeface to use when drawing text. For now, to set the
+portable typeface on the paint, call:
+
+~~~~
+ToolUtils::set_portable_typeface(SkPaint* , const char* name = nullptr,
+SkFontStyle style = SkFontStyle());
+~~~~
+
+To create a portable typeface, use:
+
+~~~~
+SkTypeface* typeface = ToolUtils::create_portable_typeface(const char* name,
+SkFontStyle style);
+~~~~
+
+Eventually, both `set_portable_typeface()` and `create_portable_typeface()` will be
+removed. Instead, a test-wide `SkFontMgr` will be selected to choose portable
+fonts or resource fonts.
+
diff --git a/site2/docs/dev/testing/fuzz.md b/site2/docs/dev/testing/fuzz.md
new file mode 100644
index 0000000..d827e4c
--- /dev/null
+++ b/site2/docs/dev/testing/fuzz.md
@@ -0,0 +1,93 @@
+
+---
+title: "Fuzzing"
+linkTitle: "Fuzzing"
+
+---
+
+
+Reproducing using `fuzz`
+------------------------
+
+We assume that you can [build Skia](/user/build). Many fuzzes only reproduce
+when building with ASAN or MSAN; see [those instructions for more details](./xsan).
+
+When building, you should add the following args to BUILD.gn to make reproducing
+less machine- and platform- dependent:
+
+    skia_use_fontconfig=false
+    skia_use_freetype=true
+    skia_use_system_freetype2=false
+    skia_use_wuffs=true
+    skia_enable_skottie=true
+    skia_enable_fontmgr_custom_directory=false
+    skia_enable_fontmgr_custom_embedded=false
+    skia_enable_fontmgr_custom_empty=true
+
+All that is needed to reproduce a fuzz downloaded from ClusterFuzz or oss-fuzz is to
+run something like:
+
+    out/ASAN/fuzz -b /path/to/downloaded/testcase
+
+The fuzz binary will try its best to guess what the type/name should be based on
+the name of the testcase. Manually providing type and name is also supported, like:
+
+    out/ASAN/fuzz -t filter_fuzz -b /path/to/downloaded/testcase
+    out/ASAN/fuzz -t api -n RasterN32Canvas -b /path/to/downloaded/testcase
+
+To enumerate all supported types and names, run the following:
+
+    out/ASAN/fuzz --help  # will list all types
+    out/ASAN/fuzz -t api  # will list all names
+
+If the crash does not show up, try to add the flag --loops:
+
+    out/ASAN/fuzz -b /path/to/downloaded/testcase --loops <times-to-run>
+
+Writing fuzzers with libfuzzer
+------------------------------
+
+libfuzzer is an easy way to write new fuzzers, and how we run them on oss-fuzz.
+Your fuzzer entry point should implement this API:
+
+    extern "C" int LLVMFuzzerTestOneInput(const uint8_t*, size_t);
+
+First install Clang and libfuzzer, e.g.
+
+    sudo apt install clang-10 libc++-10-dev libfuzzer-10-dev
+
+You should now be able to use `-fsanitize=fuzzer` with Clang.
+
+Set up GN args to use libfuzzer:
+
+    cc = "clang-10"
+    cxx = "clang++-10"
+    sanitize = "fuzzer"
+    extra_cflags = [ "-O1" ]  # Or whatever you want.
+    ...
+
+Build Skia and your fuzzer entry point:
+
+    ninja -C out/libfuzzer skia
+    clang++-10 -I. -O1 -fsanitize=fuzzer fuzz/oss_fuzz/whatever.cpp out/libfuzzer/libskia.a
+
+Run your new fuzzer binary
+
+    ./a.out
+
+
+Fuzzing Defines
+---------------
+There are some defines that can help guide a fuzzer to be more productive (e.g. avoid OOMs, avoid
+unnecessarily slow code).
+
+    // Required for fuzzing with afl-fuzz to prevent OOMs from adding noise.
+    SK_BUILD_FOR_AFL_FUZZ
+
+    // Required for fuzzing with libfuzzer
+    SK_BUILD_FOR_LIBFUZZER
+
+    // This define adds in guards to abort when we think some code path will take a long time or
+    // use a lot of RAM. It is set by default when either of the above defines are set.
+    SK_BUILD_FOR_FUZZER
+
diff --git a/site2/docs/dev/testing/ios.md b/site2/docs/dev/testing/ios.md
new file mode 100644
index 0000000..25ab660
--- /dev/null
+++ b/site2/docs/dev/testing/ios.md
@@ -0,0 +1,48 @@
+
+---
+title: "Testing on iOS"
+linkTitle: "Testing on iOS"
+
+---
+
+Before setting Skia up for automated testing from the command line, please
+follow the instructions to run Skia tests (*dm*, *nano-bench*) with the
+mainstream iOS tool chain. See the [quick start guide for ios](../../user/quick/ios).
+
+iOS doesn't lend itself well to compiling and running from the command line.
+Below are instructions on how to install a set of tools that make this possible.
+To see how they are used in automated testing please see the bash scripts
+used by the buildbot recipes: <https://github.com/google/skia/tree/master/platform_tools/ios/bin>.
+
+Installation
+------------
+The key tools are
+
+* libimobiledevice <http://www.libimobiledevice.org/>, <https://github.com/libimobiledevice/libimobiledevice>
+
+* ios-deploy <https://github.com/phonegap/ios-deploy>
+
+Follow these steps to install them:
+
+* Install Brew at <http://brew.sh/>
+* Install *libimobiledevice*
+  (Note: All these are part of the *libimobiledevice* project but packaged/developed
+  under different names. The *cask* extension to *brew* is necessary to install
+  *osxfuse* and *ifuse*, which allows to mount the application directory on an iOS device).
+
+```
+brew install libimobiledevice
+brew install ideviceinstaller
+brew install caskroom/cask/brew-cask
+brew install Caskroom/cask/osxfuse
+brew install ifuse
+```
+
+* Install node.js and ios-deploy
+
+```
+$ brew update
+$ brew install node
+$ npm install ios-deploy
+```
+
diff --git a/site2/docs/dev/testing/skiagold.md b/site2/docs/dev/testing/skiagold.md
new file mode 100644
index 0000000..6acf078
--- /dev/null
+++ b/site2/docs/dev/testing/skiagold.md
@@ -0,0 +1,185 @@
+---
+title: 'Skia Gold'
+linkTitle: 'Skia Gold'
+---
+
+## Overview
+
+Gold is a web application that compares the images produced by our bots against
+known baseline images.
+
+Key features:
+
+- Baselines are managed in Gold outside of Git, but in lockstep with Git
+  commits.
+- Each commit creates >500k images.
+- Deviations from the baseline are triaged after a CL lands and images are
+  triaged as either `positive` or `negative`. 'Positive' means the diff is
+  considered acceptable. 'Negative' means the diff is considered unacceptable
+  and requires a fix. If a CL causes Skia to break it is reverted or an
+  additional CL is landed to fix the problem.
+- We test across a range of dimensions, e.g.:
+
+  - OS (Windows, Linux, Mac, Android, iOS)
+  - Architectures (Intel, ARM)
+  - Backends (CPU, OpenGL, Vulkan etc.)
+  - etc.
+
+- Written in Go, Polymer and deployed on the Google Cloud. The code is in the
+  [Skia Infra Repository](https://github.com/google/skia-buildbot).
+
+## Recommended Workflows
+
+### How to best use Gold for commonly faced problems
+
+These instructions will refer to various views which are accessible via the left
+navigation on [gold.skia.org](https://gold.skia.org/).
+
+View access is public, triage access is granted to Skia contributors. You must
+be logged in to triage.
+
+## Problem #1: As Skia Gardener, I need to triage and “assign” many incoming new images.
+
+Solution today:
+
+- Access the By Blame view to see digests needing triage and associated
+  owners/CLs
+  - Only untriaged digests will be shown by default
+  - Blame is not sorted in any particular order
+  - Digests are clustered by runs and the most minimal set of blame
+
+<img src=BlameView.png style="margin-left:30px" align="left" width="800"/>
+<br clear="left">
+
+- Select digests for triage
+  - Digests will be listed in order with largest difference first
+  - Click to open the digest view with detailed information
+
+<img src=Digests.png style="margin-left:40px" align="left" width="780"/>
+<br clear="left">
+
+- Open bugs for identified owner(s)
+  - The digest detail view has a link to open a bug from the UI
+  - Via the Gold UI or when manually entering a bug, copy the full URL of single
+    digest into a bug report
+  - The URL reference to the digest in Issue Tracker will link the bug to the
+    digest in Gold
+
+<img src="IssueHighlight.png" style="margin-left:60px" align="left" width="720" border=1/>
+<br clear="left">
+
+<br>
+
+Future improvements:
+
+- Smarter, more granular blamelist
+
+<br>
+
+## Problem #2: As a developer, I need to land a CL that may change many images.
+
+To find your results:
+
+- Immediately following commit, access the By Blame view to find untriaged
+  digest groupings associated with your ID
+- Click on one of the clusters including your CL to triage
+- Return to the By Blame view to walk through all untriaged digests involving
+  your change
+- Note: It is not yet implemented in the UI but possible to filter the view by
+  CL. Delete hashes in the URL to only include the hash for your CL.
+
+<img src=BlameView.png style="margin-left:30px" align="left" width="800"/>
+<br clear="left">
+
+To rebaseline images:
+
+- Access the Ignores view and create a new, short-interval (hours) ignore for
+  the most affected configuration(s)
+
+<img src=Ignores.png style="margin-left:30px" align="left" width="800"/>
+<br clear="left">
+
+- Click on the Ignore to bring up a search view filtered by the affected
+  configuration(s)
+- Mark untriaged images as positive (or negative if appropriate)
+- Follow one of two options for handling former positives:
+  - Leave former positives as-is and let them fall off with time if there is low
+    risk of recurrence
+  - Mark former positives as negative if needed to verify the change moving
+    forward
+
+Future improvements:
+
+- Trybot support prior to commit, with view limited to your CL
+- Pre-triage prior to commit that will persist when the CL lands
+
+<br>
+
+## Problem #3: As a developer or infrastructure engineer, I need to add a new or updated config.
+
+(ie: new bot, test mode, environment change)
+
+Solution today:
+
+- Follow the process for rebaselining images:
+  - Wait for the bot/test/config to be committed and show up in the Gold UI
+  - Access the Ignores view and create a short-interval ignore for the
+    configuration(s)
+  - Triage the ignores for that config to identify positive images
+  - Delete the ignore
+
+Future improvements:
+
+- Introduction of a new or updated test can make use of try jobs and pre-triage.
+- New configs may be able to use these features as well.
+
+<br>
+
+## Problem #4: As a developer, I need to analyze the details of a particular image digest.
+
+Solution:
+
+- Access the By Test view
+
+<img src=ByTest.png style="margin-left:30px" align="left" width="800"/>
+<br clear="left">
+
+- Click the magnifier to filter by configuration
+- Access the Cluster view to see the distribution of digest results
+  - Use control-click to select and do a direct compare between data points
+  - Click on configurations under “parameters” to highlight data points and
+    compare
+
+<img src=ClusterConfig.png style="margin-left:30px" align="left" width="800"/>
+<br clear="left">
+
+- Access the Grid view to see NxN diffs
+
+<img src=Grid.png style="margin-left:30px" align="left" width="800"/>
+<br clear="left">
+
+- Access the Dot diagram to see history of commits for the trace
+  - Each dot represents a commit
+  - Each line represents a configuration
+  - Dot colors distinguish between digests
+
+<img src=DotDiagram.png style="margin-left:30px" align="left" width="800"/>
+<br clear="left">
+
+<br>
+
+Future improvements:
+
+- Large diff display of image vs image
+
+<br>
+
+## Problem #5: As a developer, I need to find results for a particular configuration.
+
+Solution:
+
+- Access the Search view
+- Select any parameters desired to search across tests
+
+<img src=Search.png style="margin-left:30px" align="left" width="800"/>
+<br clear="left">
diff --git a/site2/docs/dev/testing/skiaperf.md b/site2/docs/dev/testing/skiaperf.md
new file mode 100644
index 0000000..1e33148
--- /dev/null
+++ b/site2/docs/dev/testing/skiaperf.md
@@ -0,0 +1,45 @@
+
+---
+title: "Skia Perf"
+linkTitle: "Skia Perf"
+
+---
+
+
+[Skia Perf](https://perf.skia.org) is a web application for analyzing and
+viewing performance metrics produced by Skia's testing infrastructure.
+
+<img src=Perf.png style="margin-left:30px" align="left" width="800"/> <br clear="left">
+
+Skia tests across a large number of platforms and configurations, and each
+commit to Skia generates more than 400,000 individual values that are sent to
+Perf, consisting mostly of performance benchmark results, but also including
+memory and coverage data.
+
+Perf offers clustering, which is a tool to pick out trends and patterns in large sets of traces.
+
+<img src=Cluster.png style="margin-left:30px" align="left" width="400"/> <br clear="left">
+
+And can generate alerts when those trends spot a regression:
+
+<img src=Regression.png style="margin-left:30px" align="left" width="800"/> <br clear="left">
+
+
+## Calculations
+
+Skia Perf has the ability to perform calculations over the test data
+allowing you to build up interesting queries.
+
+This query displays the ratio of playback time in ms to the number of ops for desk\_wowwiki.skp:
+
+    ratio(
+      ave(fill(filter("name=desk_wowwiki.skp&sub_result=min_ms"))),
+      ave(fill(filter("name=desk_wowwiki.skp&sub_result=ops")))
+    )
+
+You can also use the data to answer questions like how many tests were run per commit.
+
+    count(filter(""))
+
+See Skia Perf for the [full list of functions available](https://perf.skia.org/help/).
+
diff --git a/site2/docs/dev/testing/skqp.md b/site2/docs/dev/testing/skqp.md
new file mode 100644
index 0000000..0a2db87
--- /dev/null
+++ b/site2/docs/dev/testing/skqp.md
@@ -0,0 +1,56 @@
+
+---
+title: "SkQP"
+linkTitle: "SkQP"
+
+---
+
+
+Development APKs of SkQP are kept in Google storage.  Each file in named
+with a abbreviated Git hash that points at the commit in the Skia repository it
+was built with.
+
+These are universal APKs that contain native libraries for armeabi-v7a,
+arm64-v8a, x86, and x86\_64 architectures. The most recent is listed first.
+
+The listing can be found here:
+[https://storage.googleapis.com/skia-skqp/apklist](https://storage.googleapis.com/skia-skqp/apklist)
+
+If you are looking at Android CTS failures, use the most recent commit on the
+`origin/skqp/release` branch.
+
+To run tests:
+
+    adb install -r skqp-universal-{APK_SHA_HERE}.apk
+    adb logcat -c
+    adb shell am instrument -w org.skia.skqp
+
+Monitor the output with:
+
+    adb logcat TestRunner org.skia.skqp skia DEBUG "*:S"
+
+Note the test's output path on the device.  It will look something like this:
+
+    01-23 15:22:12.688 27158 27173 I org.skia.skqp:
+    output written to "/storage/emulated/0/Android/data/org.skia.skqp/files/skqp_report_2019-02-28T102058"
+
+Retrieve and view the report with:
+
+    OUTPUT_LOCATION="/storage/emulated/0/Android/data/org.skia.skqp/files/skqp_report_2019-02-28T102058"
+    adb pull "$OUTPUT_LOCATION" /tmp/
+
+(Your value of `$OUTPUT_LOCATION` will differ from mine.
+
+Open the file `/tmp/output/skqp_report_2019-02-28T102058/report.html` .
+
+**Zip up that directory to attach to a bug report:**
+
+    cd /tmp
+    zip -r skqp_report_2019-02-28T102058.zip skqp_report_2019-02-28T102058
+    ls -l skqp_report_2019-02-28T102058.zip
+
+* * *
+
+For more information about building your own APK, refer to
+https://skia.googlesource.com/skia/+/master/tools/skqp/README.md
+
diff --git a/site2/docs/dev/testing/swarmingbots.md b/site2/docs/dev/testing/swarmingbots.md
new file mode 100644
index 0000000..436c426
--- /dev/null
+++ b/site2/docs/dev/testing/swarmingbots.md
@@ -0,0 +1,94 @@
+
+---
+title: "Skia Swarming Bots"
+linkTitle: "Skia Swarming Bots"
+
+---
+
+
+Overview
+--------
+
+Skia's Swarming bots are hosted in three places:
+
+* Google Compute Engine. This is the preferred location for bots which don't need to run on physical
+  hardware, ie. anything that doesn't require a GPU or a specific hardware configuration. Most of
+  our compile bots live here, along with some non-GPU test bots on Linux and Windows. We get
+  surprisingly stable performance numbers from GCE, despite very few guarantees about the physical
+  hardware.
+* Chrome Golo. This is the preferred location for bots which require specific hardware or OS
+  configurations that are not supported by GCE. We have several Mac, Linux, and Windows bots in the
+  Golo.
+* The Skolo (local Skia lab in Chapel Hill). Anything we can't get in GCE or the Golo lives
+  here. This includes a wider variety of GPUs and all Android, ChromeOS, iOS, and other devices.
+
+[go/skbl](https://goto.google.com/skbl) lists all Skia Swarming bots.
+
+
+<a name="connecting-to-swarming-bots"></a>
+Connecting to Swarming Bots
+---------------------------
+
+If you need to make changes on a bot/device, please check with the Infra Gardener or another Infra team member. Most
+bots/devices can be flashed/imaged back to a clean state, but others can not.
+
+- Machine name like “skia-e-gce-NNN”, “skia-ct-gce-NNN”, “skia-i-gce-NNN”, “ct-gce-NNN”, “ct-xxx-builder-NNN” -> GCE
+  * First determine the project for the bot:
+     + skia-e-gce-NNN, skia-ct-gce-NNN: [skia-swarming-bots](https://console.cloud.google.com/compute/instances?project=skia-swarming-bots)
+     + skia-i-gce-NNN: [google.com:skia-buildbots](https://console.cloud.google.com/compute/instances?project=google.com:skia-buildbots)
+     + ct-gce-NNN, ct-xxx-builder-NNN: [ct-swarming-bots](https://console.cloud.google.com/compute/instances?project=ct-swarming-bots)
+  * To log in to a Linux bot in GCE, use `gcloud compute ssh --project <project> default@<machine name>`. Choose the zone listed on the VM's detail page (see links above). You may also specify the zone using the `--zone` command-line flag.
+  * To log in to a Windows bot in GCE, first go to the VM's detail page and click the "Set Windows password"
+    button. (Alternatively, ask the Infra Team how to log in as chrome-bot.) There are two options to connect:
+     + SSH: Follow the instructions for Linux using your username rather than `default`.
+     + RDP: On the VM's detail page, click the "RDP" button. (You will be instructed to install the Chrome RDP Extension
+       for GCP if it hasn't already been installed.)
+
+- Machine name ends with “a9”, “m3”, "m5" -> Chrome Golo/Labs
+  * To log in to Golo bots, see [go/chrome-infra-build-access](https://goto.google.com/chrome-infra-build-access).
+
+- Machine name starts with “skia-e-”, “skia-i-” (other than “skia-i-gce-NNN”), “skia-rpi-” -> Chapel Hill lab (aka Skolo)<br/>
+  To log in to Skolo bots, see the [Skolo maintenance doc][remote access] remote access section. See the following for OS specific instructions:<br/>
+  * [Remotely debug an Android device in Skolo][remotely debug android]
+  * [VNC to Skolo Windows bots][vnc to skolo windows]
+  * [ChromeOS Debugging][chromeos debugging]
+
+
+Debugging
+---------
+
+If you need to run code on a specific machine/device to debug an issue, the simplest option is to
+run tryjobs (after adding debugging output to the relevant code). In some cases you may also need to
+[create or modify tryjobs](automated_testing#adding-new-jobs).
+
+For Googlers: If you need more control (e.g. to run GDB) and need to run directly on a swarming bot then you can use [leasing.skia.org](https://leasing.skia.org).<br/>
+If that does not work then the [current infra gardener][current infra gardener] can help you bring the device back to your desk and connect
+it to GoogleGuest Wifi or the [Google Test Network](http://go/gtn-criteria).
+
+If you need to make changes on a bot/device, please check with the Infra Gardener or another Infra team member. Most
+bots/devices can be flashed/imaged back to a clean state, but others can not.
+
+If a permanent change needs to be made on the machine (such as an OS or driver update), please [file
+a bug][infra bug] and assign to jcgregorio for reassignment.
+
+For your convenience, the machine skolo-builder is available for checking out and compiling code within the Skolo. See
+more info in the [Skolo maintenance doc][remote access] remote access section.
+
+[current infra gardener]: https://rotations.corp.google.com/rotation/4617277386260480
+[remote access]:
+    https://docs.google.com/document/d/1zTR1YtrIFBo-fRWgbUgvJNVJ-s_4_sNjTrHIoX2vulo/edit#heading=h.v77cmwbwc5la
+[infra bug]: https://bugs.chromium.org/p/skia/issues/entry?template=Infrastructure+Bug
+[remotely debug android]: https://docs.google.com/document/d/1nxn7TobfaLNNfhSTiwstOnjV0jCxYUI1uwW0T_V7BYg/
+[vnc to skolo windows]:
+    https://docs.google.com/document/d/1zTR1YtrIFBo-fRWgbUgvJNVJ-s_4_sNjTrHIoX2vulo/edit#heading=h.7cqd856ft0s
+[chromeos debugging]:
+    https://docs.google.com/document/d/1yJ2LLfLzV6pXKjiameid1LHEz1mj71Ob4wySIYxlBdw/edit#heading=h.9arg79l59xrf
+
+Maintenance Tasks
+-----------------
+
+See the [Skolo maintenance doc][skolo maintenance].
+
+[skolo maintenance]:
+    https://docs.google.com/document/d/1zTR1YtrIFBo-fRWgbUgvJNVJ-s_4_sNjTrHIoX2vulo/edit
+
diff --git a/site2/docs/dev/testing/testing.md b/site2/docs/dev/testing/testing.md
new file mode 100644
index 0000000..429fa4b
--- /dev/null
+++ b/site2/docs/dev/testing/testing.md
@@ -0,0 +1,201 @@
+---
+title: 'Correctness Testing'
+linkTitle: 'Correctness Testing'
+---
+
+Skia correctness testing is primarily served by a tool named DM. This is a
+quickstart to building and running DM.
+
+<!--?prettify lang=sh?-->
+
+    python2 tools/git-sync-deps
+    bin/gn gen out/Debug
+    ninja -C out/Debug dm
+    out/Debug/dm -v -w dm_output
+
+When you run this, you may notice your CPU peg to 100% for a while, then taper
+off to 1 or 2 active cores as the run finishes. This is intentional. DM is very
+multithreaded, but some of the work, particularly GPU-backed work, is still
+forced to run on a single thread. You can use `--threads N` to limit DM to N
+threads if you like. This can sometimes be helpful on machines that have
+relatively more CPU available than RAM.
+
+As DM runs, you ought to see a giant spew of output that looks something like
+this.
+
+```
+Skipping nonrendering: Don't understand 'nonrendering'.
+Skipping angle: Don't understand 'angle'.
+Skipping nvprmsaa4: Could not create a surface.
+492 srcs * 3 sinks + 382 tests == 1858 tasks
+
+(  25MB  1857) 1.36ms   8888 image mandrill_132x132_12x12.astc-5-subsets
+(  25MB  1856) 1.41ms   8888 image mandrill_132x132_6x6.astc-5-subsets
+(  25MB  1855) 1.35ms   8888 image mandrill_132x130_6x5.astc-5-subsets
+(  25MB  1854) 1.41ms   8888 image mandrill_132x130_12x10.astc-5-subsets
+(  25MB  1853) 151µs    8888 image mandrill_130x132_10x6.astc-5-subsets
+(  25MB  1852) 154µs    8888 image mandrill_130x130_5x5.astc-5-subsets
+                                  ...
+( 748MB     5) 9.43ms   unit test GLInterfaceValidation
+( 748MB     4) 30.3ms   unit test HalfFloatTextureTest
+( 748MB     3) 31.2ms   unit test FloatingPointTextureTest
+( 748MB     2) 32.9ms   unit test DeferredCanvas_GPU
+( 748MB     1) 49.4ms   unit test ClipCache
+( 748MB     0) 37.2ms   unit test Blur
+```
+
+Do not panic.
+
+As you become more familiar with DM, this spew may be a bit annoying. If you
+remove -v from the command line, DM will spin its progress on a single line
+rather than print a new line for each status update.
+
+Don't worry about the "Skipping something: Here's why." lines at startup. DM
+supports many test configurations, which are not all appropriate for all
+machines. These lines are a sort of FYI, mostly in case DM can't run some
+configuration you might be expecting it to run.
+
+Don't worry about the "skps: Couldn't read skps." messages either, you won't
+have those by default and can do without them. If you wish to test with them
+too, you can download them separately.
+
+The next line is an overview of the work DM is about to do.
+
+```
+492 srcs * 3 sinks + 382 tests == 1858 tasks
+```
+
+DM has found 382 unit tests (code linked in from tests/), and 492 other drawing
+sources. These drawing sources may be GM integration tests (code linked in from
+gm/), image files (from `--images`, which defaults to "resources") or .skp files
+(from `--skps`, which defaults to "skps"). You can control the types of sources
+DM will use with `--src` (default, "tests gm image skp").
+
+DM has found 3 usable ways to draw those 492 sources. This is controlled by
+`--config`. The defaults are operating system dependent. On Linux they are "8888
+gl nonrendering". DM has skipped nonrendering leaving two usable configs: 8888
+and gl. These two name different ways to draw using Skia:
+
+- 8888: draw using the software backend into a 32-bit RGBA bitmap
+- gl: draw using the OpenGL backend (Ganesh) into a 32-bit RGBA bitmap
+
+Sometimes DM calls these configs, sometimes sinks. Sorry. There are many
+possible configs but generally we pay most attention to 8888 and gl.
+
+DM always tries to draw all sources into all sinks, which is why we multiply 492
+by 3. The unit tests don't really fit into this source-sink model, so they stand
+alone. A couple thousand tasks is pretty normal. Let's look at the status line
+for one of those tasks.
+
+```
+(  25MB  1857) 1.36ms   8888 image mandrill_132x132_12x12.astc-5-subsets
+   [1]   [2]   [3]      [4]
+```
+
+This status line tells us several things.
+
+1. The maximum amount of memory DM had ever used was 25MB. Note this is a high
+   water mark, not the current memory usage. This is mostly useful for us to
+   track on our buildbots, some of which run perilously close to the system
+   memory limit.
+
+2. The number of unfinished tasks, in this example there are 1857, either
+   currently running or waiting to run. We generally run one task per hardware
+   thread available, so on a typical laptop there are probably 4 or 8 running at
+   once. Sometimes the counts appear to show up out of order, particularly at DM
+   startup; it's harmless, and doesn't affect the correctness of the run.
+
+3. Next, we see this task took 1.36 milliseconds to run. Generally, the
+   precision of this timer is around 1 microsecond. The time is purely there for
+   informational purposes, to make it easier for us to find slow tests.
+
+4. The configuration and name of the test we ran. We drew the test
+   "mandrill_132x132_12x12.astc-5-subsets", which is an "image" source, into an
+   "8888" sink.
+
+When DM finishes running, you should find a directory with file named `dm.json`,
+and some nested directories filled with lots of images.
+
+```
+$ ls dm_output
+8888    dm.json gl
+
+$ find dm_output -name '*.png'
+dm_output/8888/gm/3x3bitmaprect.png
+dm_output/8888/gm/aaclip.png
+dm_output/8888/gm/aarectmodes.png
+dm_output/8888/gm/alphagradients.png
+dm_output/8888/gm/arcofzorro.png
+dm_output/8888/gm/arithmode.png
+dm_output/8888/gm/astcbitmap.png
+dm_output/8888/gm/bezier_conic_effects.png
+dm_output/8888/gm/bezier_cubic_effects.png
+dm_output/8888/gm/bezier_quad_effects.png
+                ...
+```
+
+The directories are nested first by sink type (`--config`), then by source type
+(`--src`). The image from the task we just looked at, "8888 image
+mandrill_132x132_12x12.astc-5-subsets", can be found at
+`dm_output/8888/image/mandrill_132x132_12x12.astc-5-subsets.png`.
+
+`dm.json` is used by our automated testing system, so you can ignore it if you
+like. It contains a listing of each test run and a checksum of the image
+generated for that run.
+
+### Detail <a name="digests"></a>
+
+Boring technical detail: The checksum is not a checksum of the .png file, but
+rather a checksum of the raw pixels used to create that .png. That means it is
+possible for two different configurations to produce the same exact .png, but
+have their checksums differ.
+
+Unit tests don't generally output anything but a status update when they pass.
+If a test fails, DM will print out its assertion failures, both at the time they
+happen and then again all together after everything is done running. These
+failures are also included in the `dm.json` file.
+
+DM has a simple facility to compare against the results of a previous run:
+
+<!--?prettify lang=sh?-->
+
+    ninja -C out/Debug dm
+    out/Debug/dm -w good
+
+    # do some work
+
+    ninja -C out/Debug dm
+    out/Debug/dm -r good -w bad
+
+When using `-r`, DM will display a failure for any test that didn't produce the
+same image as the `good` run.
+
+For anything fancier, I suggest using skdiff:
+
+<!--?prettify lang=sh?-->
+
+    ninja -C out/Debug dm
+    out/Debug/dm -w good
+
+    # do some work
+
+    ninja -C out/Debug dm
+    out/Debug/dm -w bad
+
+    ninja -C out/Debug skdiff
+    mkdir diff
+    out/Debug/skdiff good bad diff
+
+    # open diff/index.html in your web browser
+
+That's the basics of DM. DM supports many other modes and flags. Here are a few
+examples you might find handy.
+
+<!--?prettify lang=sh?-->
+
+    out/Debug/dm --help        # Print all flags, their defaults, and a brief explanation of each.
+    out/Debug/dm --src tests   # Run only unit tests.
+    out/Debug/dm --nocpu       # Test only GPU-backed work.
+    out/Debug/dm --nogpu       # Test only CPU-backed work.
+    out/Debug/dm --match blur  # Run only work with "blur" in its name.
+    out/Debug/dm --dryRun      # Don't really do anything, just print out what we'd do.
diff --git a/site2/docs/dev/testing/tests.md b/site2/docs/dev/testing/tests.md
new file mode 100644
index 0000000..1ff29fd
--- /dev/null
+++ b/site2/docs/dev/testing/tests.md
@@ -0,0 +1,129 @@
+---
+title: 'Writing Skia Tests'
+linkTitle: 'Writing Skia Tests'
+---
+
+- [Unit Tests](#test)
+- [Rendering Tests](#gm)
+- [Benchmark Tests](#bench)
+
+We assume you have already synced Skia's dependencies and set up Skia's build
+system.
+
+<!--?prettify lang=sh?-->
+
+    python2 tools/git-sync-deps
+    bin/gn gen out/Debug
+    bin/gn gen out/Release --args='is_debug=false'
+
+<span id="test"></span>
+
+## Writing a Unit Test
+
+1.  Add a file `tests/NewUnitTest.cpp`:
+
+    <!--?prettify lang=cc?-->
+
+        /*
+         * Copyright ........
+         *
+         * Use of this source code is governed by a BSD-style license
+         * that can be found in the LICENSE file.
+         */
+        #include "Test.h"
+        DEF_TEST(NewUnitTest, reporter) {
+            if (1 + 1 != 2) {
+                ERRORF(reporter, "%d + %d != %d", 1, 1, 2);
+            }
+            bool lifeIsGood = true;
+            REPORTER_ASSERT(reporter, lifeIsGood);
+        }
+
+2.  Add `NewUnitTest.cpp` to `gn/tests.gni`.
+
+3.  Recompile and run test:
+
+    <!--?prettify lang=sh?-->
+
+        ninja -C out/Debug dm
+        out/Debug/dm --match NewUnitTest
+
+<span id="gm"></span>
+
+## Writing a Rendering Test
+
+1.  Add a file `gm/newgmtest.cpp`:
+
+    <!--?prettify lang=cc?-->
+
+        /*
+         * Copyright ........
+         *
+         * Use of this source code is governed by a BSD-style license
+         * that can be found in the LICENSE file.
+         */
+        #include "gm.h"
+        DEF_SIMPLE_GM(newgmtest, canvas, 128, 128) {
+            canvas->clear(SK_ColorWHITE);
+            SkPaint p;
+            p.setStrokeWidth(2);
+            canvas->drawLine(16, 16, 112, 112, p);
+        }
+
+2.  Add `newgmtest.cpp` to `gn/gm.gni`.
+
+3.  Recompile and run test:
+
+    <!--?prettify lang=sh?-->
+
+        ninja -C out/Debug dm
+        out/Debug/dm --match newgmtest
+
+4.  Run the GM inside Viewer:
+
+    <!--?prettify lang=sh?-->
+
+        ninja -C out/Debug viewer
+        out/Debug/viewer --slide GM_newgmtest
+
+<span id="bench"></span>
+
+## Writing a Benchmark Test
+
+1.  Add a file `bench/FooBench.cpp`:
+
+    <!--?prettify lang=cc?-->
+
+        /*
+         * Copyright ........
+         *
+         * Use of this source code is governed by a BSD-style license
+         * that can be found in the LICENSE file.
+         */
+        #include "Benchmark.h"
+        #include "SkCanvas.h"
+        namespace {
+        class FooBench : public Benchmark {
+        public:
+            FooBench() {}
+            virtual ~FooBench() {}
+        protected:
+            const char* onGetName() override { return "Foo"; }
+            SkIPoint onGetSize() override { return SkIPoint{100, 100}; }
+            void onDraw(int loops, SkCanvas* canvas) override {
+                while (loops-- > 0) {
+                    canvas->drawLine(0.0f, 0.0f, 100.0f, 100.0f, SkPaint());
+                }
+            }
+        };
+        }  // namespace
+        DEF_BENCH(return new FooBench;)
+
+2.  Add `FooBench.cpp` to `gn/bench.gni`.
+
+3.  Recompile and run nanobench:
+
+    <!--?prettify lang=sh?-->
+
+        ninja -C out/Release nanobench
+        out/Release/nanobench --match Foo
diff --git a/site2/docs/dev/testing/xsan.md b/site2/docs/dev/testing/xsan.md
new file mode 100644
index 0000000..f8878df
--- /dev/null
+++ b/site2/docs/dev/testing/xsan.md
@@ -0,0 +1,104 @@
+
+---
+title: "MSAN, ASAN, & TSAN"
+linkTitle: "MSAN, ASAN, & TSAN"
+
+---
+
+
+*Testing Skia with memory, address, and thread santizers.*
+
+Compiling Skia with ASAN, UBSAN, or TSAN can be done with the latest version of Clang.
+
+- UBSAN works on Linux, Mac, Android, and Windows, though some checks are platform-specific.
+- ASAN works on Linux, Mac, Android, and Windows.
+- TSAN works on Linux and Mac.
+- MSAN works on Linux[1].
+
+We find that testing sanitizer builds with libc++ uncovers more issues than
+with the system-provided C++ standard library, which is usually libstdc++.
+libc++ proactively hooks into sanitizers to help their analyses.
+We ship a copy of libc++ with our Linux toolchain in /lib.
+
+[1]To compile and run with MSAN, an MSAN-instrumented version of libc++ is needed.
+It's generally easiest to run one of the following 2 steps to build/download a recent version
+of Clang and the instrumented libc++, located in /msan.
+
+Downloading Clang binaries (Googlers Only)
+------------------------------------------
+This requires gsutil, part of the [gcloud sdk](https://cloud.google.com/sdk/downloads).
+
+<!--?prettify lang=sh?-->
+
+    CLANGDIR="${HOME}/clang"
+    python2 infra/bots/assets/clang_linux/download.py -t $CLANGDIR
+
+Building Clang binaries from scratch (Other users)
+---------------------------
+
+<!--?prettify lang=sh?-->
+
+    CLANGDIR="${HOME}/clang"
+
+    python2 tools/git-sync-deps
+    CC= CXX= infra/bots/assets/clang_linux/create.py -t "$CLANGDIR"
+
+Configure and Compile Skia with MSAN
+------------------------------------
+
+<!--?prettify lang=sh?-->
+
+    CLANGDIR="${HOME}/clang"
+    mkdir -p out/msan
+    cat > out/msan/args.gn <<- EOF
+        cc = "${CLANGDIR}/bin/clang"
+        cxx = "${CLANGDIR}/bin/clang++"
+        extra_cflags = [ "-B${CLANGDIR}/bin" ]
+        extra_ldflags = [
+            "-B${CLANGDIR}/bin",
+            "-fuse-ld=lld",
+            "-L${CLANGDIR}/msan",
+            "-Wl,-rpath,${CLANGDIR}/msan" ]
+        sanitize = "MSAN"
+        skia_use_fontconfig = false
+    EOF
+    python2 tools/git-sync-deps
+    bin/gn gen out/msan
+    ninja -C out/msan
+
+Configure and Compile Skia with ASAN
+------------------------------------
+
+<!--?prettify lang=sh?-->
+
+    CLANGDIR="${HOME}/clang"
+    mkdir -p out/asan
+    cat > out/asan/args.gn <<- EOF
+        cc = "${CLANGDIR}/bin/clang"
+        cxx = "${CLANGDIR}/bin/clang++"
+        sanitize = "ASAN"
+        extra_ldflags = [ "-fuse-ld=lld", "-Wl,-rpath,${CLANGDIR}/lib" ]
+    EOF
+    python2 tools/git-sync-deps
+    bin/gn gen out/asan
+    ninja -C out/asan
+
+Configure and Compile Skia with TSAN
+------------------------------------
+
+<!--?prettify lang=sh?-->
+
+    CLANGDIR="${HOME}/clang"
+    mkdir -p out/tsan
+    cat > out/tsan/args.gn <<- EOF
+        cc = "${CLANGDIR}/bin/clang"
+        cxx = "${CLANGDIR}/bin/clang++"
+        sanitize = "TSAN"
+        is_debug = false
+        extra_ldflags = [ "-Wl,-rpath,${CLANGDIR}/lib" ]
+    EOF
+    python2 tools/git-sync-deps
+    bin/gn gen out/tsan
+    ninja -C out/tsan
+
+
diff --git a/site2/docs/dev/tools/_index.md b/site2/docs/dev/tools/_index.md
new file mode 100644
index 0000000..180cef6
--- /dev/null
+++ b/site2/docs/dev/tools/_index.md
@@ -0,0 +1,12 @@
+
+---
+title: "Tools"
+linkTitle: "Tools"
+
+weight: 2
+
+---
+
+
+Developer tools for working in Skia.
+
diff --git a/site2/docs/dev/tools/codesearch.md b/site2/docs/dev/tools/codesearch.md
new file mode 100644
index 0000000..925a90f
--- /dev/null
+++ b/site2/docs/dev/tools/codesearch.md
@@ -0,0 +1,56 @@
+
+---
+title: "Code Search"
+linkTitle: "Code Search"
+
+---
+
+
+There are a number of ways to search the Skia codebase, each with advantages and
+disadvantages.
+
+[cs.skia.org](http://cs.skia.org) redirects to
+[Chromium code search](https://code.google.com/p/chromium/codesearch) restricted
+to the Skia portion of the Chromium tree. You can add a query after the slash;
+e.g. [cs.skia.org/foo](http://cs.skia.org/foo) will search for "foo" within the
+Skia tree. Chromium code search provides cross-references.
+
+For Googlers, there is also the option of [the skia depot](http://cs/#skia/) in
+internal Code Search. In addition to the
+main [skia](http://cs/#skia/skia/) repo, internal Code Search indexes the
+[buildbot](http://cs/#skia/buildbot/), [common](http://cs/#skia/common/),
+and [skia_internal](https://cs/#skia/skia_internal/) repos. However,
+cross-references and code analysis are not available.
+
+The GitHub mirrors of the [skia](https://github.com/google/skia) and
+[skia-buildbot](https://github.com/google/skia-buildbot) repos are useful for
+investigating history and blame, or for exploring release branches or other
+branches. However, the search functionality is fairly limited, cross-references
+are not available, and in history the original committer's username is replaced
+with that person's GitHub username.
+
+You can also navigate through the
+[Skia repos on googlesource.com](https://skia.googlesource.com/). All commits
+appear here first.
+
+  Code search option  |Search |XRef |History |Repos                         |Branches |Freshness
+  --------------------|-------|-----|--------|------------------------------|---------|---------------
+  [cs.skia.org][1]    |regexp | yes |yes     |skia [buildbot][5]            |master   |last DEPS roll
+  [Internal][2]       |regexp | no  |yes     |skia buildbot common internal |master   |hours
+  [GitHub][3]         |basic  | no  |yes     |skia buildbot                 |all      |hour
+  [googlesource][4]   |none   | no  |yes     |all                           |all      |N/A
+
+[1]: http://cs.skia.org/             "Chromium code search"
+[2]: http://cs/#skia/                "Internal Code Search"
+[3]: https://github.com/google/skia  "GitHub mirror of skia"
+[4]: https://skia.googlesource.com/  "Primary Skia repos on googlesource.com"
+[5]: https://cs.chromium.org/chromium/skia/buildbot/
+
+Client code search
+------------------
+
+There is an [internal tool for
+Googlers](https://goto.google.com/skia-client-search) to make it easier to
+search the repos of Skia clients, e.g. Chromium, Android, and Mozilla. If you
+use it and have suggestions, please let brianosman know.
+
diff --git a/site2/docs/dev/tools/debugger.md b/site2/docs/dev/tools/debugger.md
new file mode 100644
index 0000000..3e21e55
--- /dev/null
+++ b/site2/docs/dev/tools/debugger.md
@@ -0,0 +1,192 @@
+---
+title: 'Skia Debugger'
+linkTitle: 'Skia Debugger'
+---
+
+## Introduction
+
+The Skia Debugger is a graphical tool used to step through and analyze the
+contents of the Skia picture format. The tool is available online at
+[https://debugger.skia.org](https://debugger.skia.org/) or can be run locally.
+
+Features:
+
+- Draw command and multiple frame playback
+- Shows the current clip and matrix at any step
+- Zoomed viewer with crosshair for selecting pixels.
+- Breakpoints that stop playback when a pixel's color changes.
+- GPU or CPU backed execution.
+- GPU op bounds visualization
+- Android offscreen layer visualization
+- Shared resource viewer
+
+<img src="/dev/tools/onlinedebugger.png" style="display: inline-block;" />
+
+## User Guide
+
+SKP files can contain a single frame or multiple frames. Single frame files have
+the .skp extension and Multi-frame files have the .mskp extension. In the online
+debugger linked above, Open a [sample mskp file](/dev/tools/calendar.mskp) or
+capture one from an android device using the
+[instructions here](https://sites.google.com/a/google.com/skia/android/skp-from-framework).
+
+### Command Playback and Filters
+
+Try playing back the commands within the current frame using the lower play
+button <img src="/dev/tools/playcommands.png" style="display: inline-block;" />,
+(the one not in a circle) You should see the image built up one draw at a time.
+
+Many commands manipulate the matrix or clip but don't make any visible change
+when run. Try filtering these out by pasting
+`!drawannotation save restore concat setmatrix cliprect` in to the filter
+textbox just below the command playback controls. Press enter to apply the
+filter, and resume playback if it was paused. This will have the effect of
+making the playback appear to be much faster as there are only 29 commands in
+the first frame of the sample file that pass this filter.
+
+Try pausing command playback and stepping forward and back through the commands
+using `,` (comma) and `.` (period).
+
+> Filters are case insensitive, and the only supported logical operator is !
+> (not) which applies to the entire filter and is only recognised when it occurs
+> at the beginning.
+
+Any command can be expanded using the
+<img src="/dev/tools/expand.png" style="display: inline-block;" /> icon to see
+all of the parameters that were recorded with that command.
+
+Commands can be disabled or enabled with the checkbox that becomes available
+after expanding the command's detail view.
+
+Jog the command playhead to the end of the list with the
+<img src="/dev/tools/end.png" style="display: inline-block;" /> button.
+
+### Frame playback
+
+<img src="/dev/tools/frameplayback.png" style="display: inline-block;" />
+
+The sample file contains multiple frames. Use the encircled play button to play
+back the frames. The current frame is indictated by the slider position, and the
+slider can be set manually. Frames can be stepped through with `w` (back) and
+`s` forward. `p` pauses or unpauses the frame playback.
+
+Not all frames in a file will have the same number of commands. When the command
+playhead is left at the end of the list the debugger will play every frame to
+the end of its list. If the command playhead is somewhere in the middle, say
+155, the debugger will try to play every frame to its 155th command.
+
+### Resources Tab
+
+<img src="/dev/tools/resources.png" style="display: inline-block;" />
+
+Any resources that were referenced by commands in the file appear here. As of
+Dec 2019, this only shows images.
+
+Any resource can be selected and viewed. You may find it helpful to toggle the
+Light/Dark setting if you cannot see an image.
+
+Images' names are formatted as `7 @24205864 (99, 99)` where `7` is the index of
+the image as it was saved in the file, `@24205864` is it's address in wasm
+memory, for cross referencing with DrawImage\* commands in the command list
+which also show this address, and `(99, 99)` is the size of the image.
+
+The resource viewer allows a user to determine if an image was not effectively
+shared between frames or draw commands. If it occurs more than once in the
+resource tab, then there were multiple copies of it with different generation
+ids in the process that recorded the SKP.
+
+### Android Layers
+
+<img src="/dev/tools/layers.png" style="display: inline-block;" />
+
+When MSKPs are recorded in Android, Extra information about offscreen hardware
+layers is recorded. The sample google calendar mskp linked above contains this
+information. You will find two layers on frame 3.
+
+There are two kinds of events relevant to recorded android layer use.
+
+1. Draw Events - points when an offscreen surface was drawn to. They may be
+   complete, meaning the clip equalled the surface's size, or partial, meaning
+   the clip was smaller.
+2. Use events - points when the offscreen surface was used as an SkImage in the
+   main surface.
+
+Layers are shown as boxes in the bottom right of the interface when viewing a
+frame where a layer draw event occurred. Each Layer box has two buttons:
+`Show Use` will cycle through use events for that layer in the current frame if
+there are any, and `Inspector` will open the draw event as if it were a single
+frame SKP. you can play back it's commands, enable or disabled them, inspect GPU
+op bounds or anything else you could do with an ordinary SKP. Exit the inspector
+by clicking the `Exit` button on the layer box.
+
+### Crosshair and Breakpoints
+
+<img src="/dev/tools/crosshair.png" style="display: inline-block;" />
+
+Clicking any point in the main view will toggle a red crosshair for selecting
+pixels. the selected pixel's color is shown in several formats on the right
+pane. A zoomed view centered on the selected pixel is shown below it. The
+position can be moved precicely by either clicking neighboring pixels in the
+zoom view, or using `H` (left) `L` (right) `J` (down) `K` (up).
+
+When "Break on change" is selected, command playback will pause on any command
+which changes the color of the selected pixel. this can be used to find the
+command that draws something you see in the viewer.
+
+### GPU Op Bounds and Other settings
+
+<img src="/dev/tools/settings.png" style="display: inline-block;" />
+
+Each of the filtered commands from above has a colored number to its right
+<img src="/dev/tools/gpuop.png" style="display: inline-block;" />. This is the
+GPU operation id. When multiple commands share a GPU op id, this indicates that
+they were batched together when sent to the GPU. In the WASM debugger, this goes
+though WebGL.
+
+There is a "Display GPU Op Bounds" toggle in the upper right of the interface.
+Turning this on will show a colored rectangle to represent the bounds of the GPU
+op of the currently selected command.
+
+GPU - Controls which backend Skia uses to draw to the screen. GPU in the online
+wasm debugger means WebGL. CPU means skia draws into a surface in memory which
+is copied into an HTML canvas without using the GPU.
+
+Light/Dark - this toggle changes the appearance of the checkerboard behind the
+main view and zoom views to assist in viewing content with transparency.
+
+Display Overdraw Viz - This vizualization shows a red overlay that is darker in
+propertion to how much overdraw has occurred on a pixel. Overdraw meaning that
+the pixel was drawn to more than once.
+
+- As of Dec 2019, this feature may not be working correctly.
+
+### Image fit and download buttons.
+
+<img src="/dev/tools/settings.png" style="display: inline-block;" />
+
+These buttons resize the main view. they are, from left to right:
+
+Original size - the natural size of the canvas, when it was recorded. Fit to
+page - shrink enough that the whole canvas fits in the center pane. Fit to page
+width - make the canvas fit horizontally but allow scrolling vertically Fit to
+page height - make the canvas fit vertically but allow scrolling horizontally.
+
+next to these is a 5th, unrelated download button which saves the current canvas
+as a PNG file.
+
+## Building and running locally
+
+Begin by following the instructions to
+[download and build Skia](../../user/quick), then simply build and run the
+`skiaserve` tool:
+
+<!--?prettify lang=sh?-->
+
+    # Build.
+    ninja -C out/Release skiaserve
+
+    # Run the debugger locally
+    out/Release/skiaserve
+
+After running `skiaserve`, follow the instructions to open the debugger in your
+local browser. By default the address will be `http://127.0.0.1:8888`.
diff --git a/site2/docs/dev/tools/debugvis.md b/site2/docs/dev/tools/debugvis.md
new file mode 100644
index 0000000..09ee7dd
--- /dev/null
+++ b/site2/docs/dev/tools/debugvis.md
@@ -0,0 +1,18 @@
+
+---
+title: "Debug Visualization"
+linkTitle: "Debug Visualization"
+
+---
+
+
+Skia uses custom container types, such as `SkString` and `SkTArray<>`, which can
+be inconvenient to view in a debugger.
+
+If you frequently debug code that uses Skia types, consider installing a debug
+visualizer. Skia offers debugger visualization support for the following
+platforms:
+
+-   [Visual Studio and VS Code](https://skia.googlesource.com/skia/+/refs/heads/master/platform_tools/debugging/vs/Skia.natvis)
+-   [LLDB and Xcode](https://skia.googlesource.com/skia/+/refs/heads/master/platform_tools/debugging/lldb/skia.py)
+
diff --git a/site2/docs/dev/tools/markdown.md b/site2/docs/dev/tools/markdown.md
new file mode 100644
index 0000000..732da88
--- /dev/null
+++ b/site2/docs/dev/tools/markdown.md
@@ -0,0 +1,52 @@
+---
+title: 'Markdown'
+linkTitle: 'Markdown'
+---
+
+This site is build with [Hugo](https://gohugo.io/) and
+[Docsy](https://www.docsy.dev/).
+
+Any file you put under `/site/` that has the extension `.md` will be processed
+as Markdown. All other files will be served directly. For example, images can be
+added and they will be served correctly and referenced from within Markdown
+files.
+
+When preparing for a code review of site docs you can get a preview of how the
+page will render by visiting the skia.org site and add a query parameter `cl`
+with the value of the Reitveld issue id:
+
+    https://skia.org/path/to/markdown-file?cl=REITVELD_ISSUE_NUMBER
+
+See the [Docsy documentation](https://www.docsy.dev/docs/) for more details on
+how to configure and use docsy. For example the
+[Navigation](https://www.docsy.dev/docs/adding-content/navigation/) section
+explains what frontmatter needs to be added to a page to get it to appear in the
+top navigation bar.
+
+## Frontmatter
+
+Each page needs a frontmatter section that provides information on that page.
+For example:
+
+```
+---
+title: 'Markdown'
+linkTitle: 'Markdown'
+---
+```
+
+This is true for both Markdown and HTML pages. See
+[the Docsy documentation on frontmatter](https://www.docsy.dev/docs/adding-content/content/#page-frontmatter)
+for more details.
+
+## Styling And Icons
+
+Docsy supports both
+[Bootstrap](https://getbootstrap.com/docs/5.0/getting-started/introduction/) and
+[Font-Awesome](https://fontawesome.com/). Check out their documentation for what
+they offer.
+
+## Configuration
+
+The Hugo configuration file is [config.toml](../../../config.toml) in the site
+directory.
diff --git a/site2/docs/dev/tools/tracing.md b/site2/docs/dev/tools/tracing.md
new file mode 100644
index 0000000..ad7057c
--- /dev/null
+++ b/site2/docs/dev/tools/tracing.md
@@ -0,0 +1,115 @@
+
+---
+title: "Tracing Skia Execution"
+linkTitle: "Tracing Skia Execution"
+
+---
+
+
+Introduction
+------------
+
+Skia is instrumented to provide execution traces in several ways. Within Chrome, Skia is traced
+with the standard [tracing interface](chrome://tracing), along with the rest of Chromium. In
+the Android framework, Skia's tracing is integrated into
+[atrace](https://source.android.com/devices/tech/debug/ftrace).
+
+For standalone builds, Skia's tools (DM, nanobench, and Viewer) are capable of tracing execution
+in three ways, controlled by the `--trace` command line argument.
+
+Standalone Tracing
+------------------
+
+Most arguments to `--trace` will be interpreted as a filename (the two exceptions are described
+below), and trace events will be written to that file in JSON format, suitable for viewing with
+[chrome://tracing](chrome://tracing).
+
+<!--?prettify lang=sh?-->
+
+    # Run DM on several GMs to get tracing data
+    out/Release/dm --config gl --match bleed --trace gl_bleed_gms.json
+
+This creates a file `gl_bleed_gms.json` in the current directory. There are limitations in Chrome's
+tracing tool that prevent loading a file larger than 256 MB. To stay under that limit (and avoid
+clutter and slowdown in the interface), it's best to run a small number of tests/benchmarks when
+tracing. Once you have generated a file in this way, go to
+[chrome://tracing](chrome://tracing), click Load:
+
+![Load Button](tracing_load.png)
+
+... then select the JSON file. The data will be loaded and can be navigated/inspected using the
+tracing tools. Tip: press '?' for a help screen explaining the available keyboard and mouse
+controls.
+
+![Tracing interface](tracing.png)
+
+Android ATrace
+--------------
+
+Running any tool with `--trace atrace` on an Android device will cause the application to forward
+tracing information to [atrace](https://source.android.com/devices/tech/debug/ftrace). On other
+platforms, this has no effect.
+
+If you run `systrace` from the host command line, you will need to supply `-a <app_name>`,
+and the `<app_name>` argument will need to exactly match the command line used on the target
+device. For example, if you use `adb shell "cd /data/local/tmp; ./nanobench --trace atrace ..."`
+you must pass `-a ./nanobench` or systrace will ignore events from the application.
+
+Console Logging
+---------------
+
+For simple situations, all tracing events can be directed to the console with `--trace debugf`:
+
+<!--?prettify lang=sh?-->
+
+    # Run DM on a single GM with SkDebugf tracing
+    out/Release/dm --config gl --match ^gamma$ --trace debugf
+
+~~~
+[ 0] <skia.gpu> GrDrawingManager::internalFlush id=1 #0 {
+[ 0] } GrDrawingManager::internalFlush
+[ 0] <skia.gpu> GrGpu::createTexture id=1 #1 {
+[ 0] } GrGpu::createTexture
+[ 0] <skia.gpu> GrRenderTargetContext::discard id=1 #2 {
+[ 0] } GrRenderTargetContext::discard
+[ 0] <skia.gpu> SkGpuDevice::clearAll id=1 #3 {
+[ 1]  <skia.gpu> GrRenderTargetContext::clear id=1 #4 {
+[ 1]  } GrRenderTargetContext::clear
+[ 0] } SkGpuDevice::clearAll
+[ 0] <skia> SkCanvas::drawRect() #5 {
+[ 1]  <skia.gpu> SkGpuDevice::drawRect id=1 #6 {
+[ 2]   <skia.gpu> GrRenderTargetContext::drawRect id=1 #7 {
+[ 3]    <skia.gpu> GrRenderTargetContext::addDrawOp id=1 #8 {
+[ 3]    } GrRenderTargetContext::addDrawOp
+[ 2]   } GrRenderTargetContext::drawRect
+[ 1]  } SkGpuDevice::drawRect
+[ 0] } SkCanvas::drawRect()
+...
+~~~
+
+Adding More Trace Events
+------------------------
+
+Adding more trace events involves using a set of `TRACE_` macros. The simplest example, to record
+the time spent in a function or other scope, is:
+
+~~~
+#include "SkTraceEvent.h"
+...
+void doSomething() {
+  // Add an event for the duration of the current function (or other scope)
+  // "skia" is a category name, for filtering events while recording
+  // TRACE_FUNC is the event name, and expands to the name of the current function
+  TRACE_EVENT0("skia", TRACE_FUNC);
+
+  if (doExtraWork) {
+    TRACE_EVENT0("skia", "ExtraWorkBeingDone");
+    ...
+  }
+}
+~~~
+
+For more examples, including other kinds of trace events and attaching parameters to events, see
+the comments in
+[SkTraceEventCommon.h](https://cs.chromium.org/chromium/src/third_party/skia/src/core/SkTraceEventCommon.h).
+