141fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com/* 241fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com * Copyright 2011 Google Inc. 341fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com * 441fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com * Use of this source code is governed by a BSD-style license that can be 541fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com * found in the LICENSE file. 641fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com */ 741fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com#include "gm.h" 833d2055e594177b27360f84e0631b26d74a55a9bMike Klein#include "sk_tool_utils.h" 941fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com#include "SkCanvas.h" 1041fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com#include "SkGradientShader.h" 11d3ebb48320cf1b7e969974673e4bd7743816985ebungeman#include "SkPath.h" 1241fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 13dac522589e9395b4654a1a708f1bd971f37f95a5commit-bot@chromium.orgstatic void makebm(SkBitmap* bm, int w, int h) { 14dac522589e9395b4654a1a708f1bd971f37f95a5commit-bot@chromium.org bm->allocN32Pixels(w, h); 15dbfac8a72393eaf01670aeb3244de0e18d8faf98junov@google.com bm->eraseColor(SK_ColorTRANSPARENT); 1641fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 1741fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkCanvas canvas(*bm); 1841fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkScalar s = SkIntToScalar(SkMin32(w, h)); 19dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein const SkPoint kPts0[] = { { 0, 0 }, { s, s } }; 20dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein const SkPoint kPts1[] = { { s, 0 }, { 0, s } }; 21dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein const SkScalar kPos[] = { 0, SK_Scalar1/2, SK_Scalar1 }; 22dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein const SkColor kColors0[] = {0x40FF00FF, 0xF0FFFF00, 0x4000FFFF }; 23dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein const SkColor kColors1[] = {0xF0FF00FF, 0x80FFFF00, 0xF000FFFF }; 24fc84359aa920567e72742877a1249f52d076ad35skia.committer@gmail.com 2541fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 2641fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkPaint paint; 2741fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 281a9b9640843a64af8d9d90337ec3b3fea663196areed paint.setShader(SkGradientShader::MakeLinear(kPts0, kColors0, kPos, 291a9b9640843a64af8d9d90337ec3b3fea663196areed SK_ARRAY_COUNT(kColors0), SkShader::kClamp_TileMode)); 3041fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas.drawPaint(paint); 311a9b9640843a64af8d9d90337ec3b3fea663196areed paint.setShader(SkGradientShader::MakeLinear(kPts1, kColors1, kPos, 321a9b9640843a64af8d9d90337ec3b3fea663196areed SK_ARRAY_COUNT(kColors1), SkShader::kClamp_TileMode)); 3341fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas.drawPaint(paint); 3441fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com} 3541fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 3641fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com/////////////////////////////////////////////////////////////////////////////// 3741fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 3841fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.comstruct LabeledMatrix { 3941fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkMatrix fMatrix; 4041fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com const char* fLabel; 4141fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com}; 4241fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 432a24338c777462e04a2b26295f9c034155ee8f3ehalcanaryDEF_SIMPLE_GM_BG(shadertext2, canvas, 1800, 900, 442a24338c777462e04a2b26295f9c034155ee8f3ehalcanary sk_tool_utils::color_to_565(0xFFDDDDDD)) { 45dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein constexpr char kText[] = "SKIA"; 46dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein constexpr int kTextLen = SK_ARRAY_COUNT(kText) - 1; 47dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein constexpr int kPointSize = 55; 4841fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 4941fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkTDArray<LabeledMatrix> matrices; 5041fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com matrices.append()->fMatrix.reset(); 5141fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com matrices.top().fLabel = "Identity"; 5241fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com matrices.append()->fMatrix.setScale(1.2f, 0.8f); 5341fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com matrices.top().fLabel = "Scale"; 5441fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com matrices.append()->fMatrix.setRotate(10.f); 5541fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com matrices.top().fLabel = "Rotate"; 5641fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com matrices.append()->fMatrix.reset(); 5741fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com matrices.top().fMatrix.setPerspX(-0.0015f); 5841fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com matrices.top().fMatrix.setPerspY(+0.0015f); 5941fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com matrices.top().fLabel = "Persp"; 6041fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 6141fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkTDArray<LabeledMatrix> localMatrices; 6241fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com localMatrices.append()->fMatrix.reset(); 6341fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com localMatrices.top().fLabel = "Identity"; 6441fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com localMatrices.append()->fMatrix.setScale(2.5f, 0.2f); 6541fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com localMatrices.top().fLabel = "Scale"; 6641fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com localMatrices.append()->fMatrix.setRotate(45.f); 6741fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com localMatrices.top().fLabel = "Rotate"; 6841fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com localMatrices.append()->fMatrix.reset(); 6941fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com localMatrices.top().fMatrix.setPerspX(-0.007f); 7041fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com localMatrices.top().fMatrix.setPerspY(+0.008f); 7141fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com localMatrices.top().fLabel = "Persp"; 7241fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 7341fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com static SkBitmap bmp; 7441fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com if (bmp.isNull()) { 75dac522589e9395b4654a1a708f1bd971f37f95a5commit-bot@chromium.org makebm(&bmp, kPointSize / 2, kPointSize / 2); 7641fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com } 77fc84359aa920567e72742877a1249f52d076ad35skia.committer@gmail.com 7841fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkPaint fillPaint; 7941fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com fillPaint.setAntiAlias(true); 801818acb6a4b11cd9a1d44ce5dde77452502a9796caryclark sk_tool_utils::set_portable_typeface(&fillPaint); 8141fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com fillPaint.setTextSize(SkIntToScalar(kPointSize)); 8293a1215fe0ab007ce941c721f1fd3e9dcb5d4754reed fillPaint.setFilterQuality(kLow_SkFilterQuality); 8341fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 8441fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkPaint outlinePaint; 8541fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com outlinePaint.setAntiAlias(true); 861818acb6a4b11cd9a1d44ce5dde77452502a9796caryclark sk_tool_utils::set_portable_typeface(&outlinePaint); 8741fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com outlinePaint.setTextSize(SkIntToScalar(kPointSize)); 8841fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com outlinePaint.setStyle(SkPaint::kStroke_Style); 8941fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com outlinePaint.setStrokeWidth(0.f); 9041fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 9141fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkScalar w = fillPaint.measureText(kText, kTextLen); 9241fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com static SkScalar kPadY = 0.5f * kPointSize; 9341fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com static SkScalar kPadX = 1.5f * kPointSize; 9441fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 9541fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkPaint strokePaint(fillPaint); 9641fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com strokePaint.setStyle(SkPaint::kStroke_Style); 9741fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com strokePaint.setStrokeWidth(kPointSize * 0.1f); 9841fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 9941fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkPaint labelPaint; 10041fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com labelPaint.setColor(0xff000000); 10141fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com labelPaint.setAntiAlias(true); 1021818acb6a4b11cd9a1d44ce5dde77452502a9796caryclark sk_tool_utils::set_portable_typeface(&labelPaint); 10341fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com labelPaint.setTextSize(12.f); 10441fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 10541fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->translate(15.f, 15.f); 10641fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->drawBitmap(bmp, 0, 0); 10741fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->translate(0, bmp.height() + labelPaint.getTextSize() + 15.f); 10841fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 109dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein constexpr char kLabelLabel[] = "localM / canvasM"; 1102a475eae622adc1e8fa29206be1eaf862c23548eCary Clark canvas->drawString(kLabelLabel, 0, 0, labelPaint); 11141fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->translate(0, 15.f); 11241fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 11341fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->save(); 11441fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkScalar maxLabelW = 0; 11541fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->translate(0, kPadY / 2 + kPointSize); 11641fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com for (int lm = 0; lm < localMatrices.count(); ++lm) { 1172a475eae622adc1e8fa29206be1eaf862c23548eCary Clark canvas->drawString(matrices[lm].fLabel, 11841fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 0, labelPaint.getTextSize() - 1, labelPaint); 11941fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkScalar labelW = labelPaint.measureText(matrices[lm].fLabel, 12041fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com strlen(matrices[lm].fLabel)); 12141fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com maxLabelW = SkMaxScalar(maxLabelW, labelW); 12241fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->translate(0.f, 2 * kPointSize + 2.5f * kPadY); 12341fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com } 12441fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->restore(); 12541fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 12641fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->translate(maxLabelW + kPadX / 2.f, 0.f); 12741fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 12841fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com for (int s = 0; s < 2; ++s) { 12941fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkPaint& paint = s ? strokePaint : fillPaint; 13041fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 13135d4872f9a4d49395dd387677eb828ce0e8176bfcommit-bot@chromium.org SkScalar columnH = 0; 13241fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com for (int m = 0; m < matrices.count(); ++m) { 13341fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com columnH = 0; 13441fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->save(); 1352a475eae622adc1e8fa29206be1eaf862c23548eCary Clark canvas->drawString(matrices[m].fLabel, 13641fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 0, labelPaint.getTextSize() - 1, labelPaint); 13741fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->translate(0, kPadY / 2 + kPointSize); 13841fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com columnH += kPadY / 2 + kPointSize; 13941fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com for (int lm = 0; lm < localMatrices.count(); ++lm) { 1401a9b9640843a64af8d9d90337ec3b3fea663196areed paint.setShader(SkShader::MakeBitmapShader(bmp, SkShader::kMirror_TileMode, 1411a9b9640843a64af8d9d90337ec3b3fea663196areed SkShader::kRepeat_TileMode, 1421a9b9640843a64af8d9d90337ec3b3fea663196areed &localMatrices[lm].fMatrix)); 14341fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 14441fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->save(); 14541fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->concat(matrices[m].fMatrix); 14641fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->drawText(kText, kTextLen, 0, 0, paint); 14741fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->drawText(kText, kTextLen, 0, 0, outlinePaint); 14841fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->restore(); 14941fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 15041fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkPath path; 15141fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com path.arcTo(SkRect::MakeXYWH(-0.1f * w, 0.f, 15241fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 1.2f * w, 2.f * kPointSize), 15341fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 225.f, 359.f, 15441fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com false); 15541fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com path.close(); 15641fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 15741fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->translate(0.f, kPointSize + kPadY); 15841fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com columnH += kPointSize + kPadY; 15941fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com 16041fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->save(); 16141fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->concat(matrices[m].fMatrix); 16296fcdcc219d2a0d3579719b84b28bede76efba64halcanary canvas->drawTextOnPath(kText, kTextLen, path, nullptr, paint); 16396fcdcc219d2a0d3579719b84b28bede76efba64halcanary canvas->drawTextOnPath(kText, kTextLen, path, nullptr, outlinePaint); 16441fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->restore(); 16541fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkPaint stroke; 16641fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com stroke.setStyle(SkPaint::kStroke_Style); 16741fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->translate(0.f, kPointSize + kPadY); 16841fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com columnH += kPointSize + kPadY; 16941fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com } 17041fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->restore(); 17141fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->translate(w + kPadX, 0.f); 17241fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com } 17341fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com if (0 == s) { 17441fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->drawLine(0.f, -kPadY, 0.f, columnH + kPadY, outlinePaint); 17541fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com canvas->translate(kPadX / 2, 0.f); 176dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein constexpr char kFillLabel[] = "Filled"; 177dbfd7ab10883f173f5c1b653a233e18dc6142002mtklein constexpr char kStrokeLabel[] = "Stroked"; 17841fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkScalar y = columnH + kPadY / 2; 17941fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkScalar fillX = -outlinePaint.measureText(kFillLabel, strlen(kFillLabel)) - kPadX; 18041fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com SkScalar strokeX = kPadX; 1812a475eae622adc1e8fa29206be1eaf862c23548eCary Clark canvas->drawString(kFillLabel, fillX, y, labelPaint); 1822a475eae622adc1e8fa29206be1eaf862c23548eCary Clark canvas->drawString(kStrokeLabel, strokeX, y, labelPaint); 18341fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com } 18441fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com } 18541fe45b955dc2f572bb1b6598d3b2f9d0c0447a4bsalomon@google.com} 186