Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(141)

Side by Side Diff: tools/PictureRenderer.h

Issue 1457753002: Clean up dead code: PictureRenderer (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: rebase? Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « gyp/tools.gyp ('k') | tools/PictureRenderer.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #ifndef PictureRenderer_DEFINED
9 #define PictureRenderer_DEFINED
10
11 #include "SkCanvas.h"
12 #include "SkDrawFilter.h"
13 #include "SkJSONCPP.h"
14 #include "SkMath.h"
15 #include "SkPaint.h"
16 #include "SkPicture.h"
17 #include "SkPictureRecorder.h"
18 #include "SkRect.h"
19 #include "SkRefCnt.h"
20 #include "SkString.h"
21 #include "SkTDArray.h"
22 #include "SkTypes.h"
23
24 #if SK_SUPPORT_GPU
25 #include "GrContextFactory.h"
26 #include "GrContext.h"
27 #endif
28
29 struct GrContextOptions;
30 class SkBitmap;
31 class SkCanvas;
32 class SkGLContext;
33 class SkThread;
34
35 namespace sk_tools {
36
37 class TiledPictureRenderer;
38
39 class PictureRenderer : public SkRefCnt {
40
41 public:
42 enum SkDeviceTypes {
43 #if SK_ANGLE
44 kAngle_DeviceType,
45 #endif
46 #if SK_COMMAND_BUFFER
47 kCommandBuffer_DeviceType,
48 #endif
49 #if SK_MESA
50 kMesa_DeviceType,
51 #endif
52 kBitmap_DeviceType,
53 #if SK_SUPPORT_GPU
54 kGPU_DeviceType,
55 kNVPR_DeviceType,
56 #endif
57 };
58
59 enum BBoxHierarchyType {
60 kNone_BBoxHierarchyType = 0,
61 kRTree_BBoxHierarchyType,
62
63 kLast_BBoxHierarchyType = kRTree_BBoxHierarchyType,
64 };
65
66 // this uses SkPaint::Flags as a base and adds additional flags
67 enum DrawFilterFlags {
68 kNone_DrawFilterFlag = 0,
69 kHinting_DrawFilterFlag = 0x10000, // toggles between no hinting and nor mal hinting
70 kSlightHinting_DrawFilterFlag = 0x20000, // toggles between slight and n ormal hinting
71 kAAClip_DrawFilterFlag = 0x40000, // toggles between soft and hard clip
72 kMaskFilter_DrawFilterFlag = 0x80000, // toggles on/off mask filters (e. g., blurs)
73 };
74
75 static_assert(!(kMaskFilter_DrawFilterFlag & SkPaint::kAllFlags),
76 "maskfilter_flag_must_be_greater");
77 static_assert(!(kHinting_DrawFilterFlag & SkPaint::kAllFlags),
78 "hinting_flag_must_be_greater");
79 static_assert(!(kSlightHinting_DrawFilterFlag & SkPaint::kAllFlags),
80 "slight_hinting_flag_must_be_greater");
81
82 /**
83 * Called with each new SkPicture to render.
84 *
85 * @param pict The SkPicture to render.
86 * @param writePath The output directory within which this renderer should w rite all images,
87 * or nullptr if this renderer should not write all images.
88 * @param mismatchPath The output directory within which this renderer shoul d write any images
89 * which do not match expectations, or nullptr if this renderer should n ot write mismatches.
90 * @param inputFilename The name of the input file we are rendering.
91 * @param useChecksumBasedFilenames Whether to use checksum-based filenames when writing
92 * bitmap images to disk.
93 * @param useMultiPictureDraw true if MultiPictureDraw should be used for re ndering
94 */
95 virtual void init(const SkPicture* pict,
96 const SkString* writePath,
97 const SkString* mismatchPath,
98 const SkString* inputFilename,
99 bool useChecksumBasedFilenames,
100 bool useMultiPictureDraw);
101
102 /**
103 * Set the viewport so that only the portion listed gets drawn.
104 */
105 void setViewport(SkISize size) { fViewport = size; }
106
107 /**
108 * Set the scale factor at which draw the picture.
109 */
110 void setScaleFactor(SkScalar scale) { fScaleFactor = scale; }
111
112 /**
113 * Perform any setup that should done prior to each iteration of render() wh ich should not be
114 * timed.
115 */
116 virtual void setup() {}
117
118 /**
119 * Perform the work. If this is being called within the context of bench_pi ctures,
120 * this is the step that will be timed.
121 *
122 * Typically "the work" is rendering an SkPicture into a bitmap, but in some subclasses
123 * it is recording the source SkPicture into another SkPicture.
124 *
125 * If fWritePath has been specified, the result of the work will be written to that dir.
126 * If fMismatchPath has been specified, and the actual image result differs from its
127 * expectation, the result of the work will be written to that dir.
128 *
129 * @param out If non-null, the implementing subclass MAY allocate an SkBitma p, copy the
130 * output image into it, and return it here. (Some subclasses ig nore this parameter)
131 * @return bool True if rendering succeeded and, if fWritePath had been spec ified, the output
132 * was successfully written to a file.
133 */
134 virtual bool render(SkBitmap** out = nullptr) = 0;
135
136 /**
137 * Called once finished with a particular SkPicture, before calling init aga in, and before
138 * being done with this Renderer.
139 */
140 virtual void end();
141
142 /**
143 * If this PictureRenderer is actually a TiledPictureRender, return a pointe r to this as a
144 * TiledPictureRender so its methods can be called.
145 */
146 virtual TiledPictureRenderer* getTiledRenderer() { return nullptr; }
147
148 /**
149 * Resets the GPU's state. Does nothing if the backing is raster. For a GPU renderer, calls
150 * flush, swapBuffers and, if callFinish is true, finish.
151 * @param callFinish Whether to call finish.
152 */
153 void resetState(bool callFinish);
154
155 /**
156 * Remove all decoded textures from the CPU caches and all uploaded textures
157 * from the GPU.
158 */
159 void purgeTextures();
160
161 /**
162 * Set the backend type. Returns true on success and false on failure.
163 */
164 #if SK_SUPPORT_GPU
165 bool setDeviceType(SkDeviceTypes deviceType, GrGLStandard gpuAPI = kNone_GrG LStandard) {
166 #else
167 bool setDeviceType(SkDeviceTypes deviceType) {
168 #endif
169 fDeviceType = deviceType;
170 #if SK_SUPPORT_GPU
171 // In case this function is called more than once
172 SkSafeUnref(fGrContext);
173 fGrContext = nullptr;
174 // Set to Native so it will have an initial value.
175 GrContextFactory::GLContextType glContextType = GrContextFactory::kNativ e_GLContextType;
176 #endif
177 switch(deviceType) {
178 case kBitmap_DeviceType:
179 return true;
180 #if SK_SUPPORT_GPU
181 case kGPU_DeviceType:
182 // Already set to GrContextFactory::kNative_GLContextType, above .
183 break;
184 case kNVPR_DeviceType:
185 glContextType = GrContextFactory::kNVPR_GLContextType;
186 break;
187 #if SK_ANGLE
188 case kAngle_DeviceType:
189 glContextType = GrContextFactory::kANGLE_GLContextType;
190 break;
191 #endif
192 #if SK_COMMAND_BUFFER
193 case kCommandBuffer_DeviceType:
194 glContextType = GrContextFactory::kCommandBuffer_GLContextType;
195 break;
196 #endif
197 #if SK_MESA
198 case kMesa_DeviceType:
199 glContextType = GrContextFactory::kMESA_GLContextType;
200 break;
201 #endif
202 #endif
203 default:
204 // Invalid device type.
205 return false;
206 }
207 #if SK_SUPPORT_GPU
208 fGrContext = fGrContextFactory.get(glContextType, gpuAPI);
209 if (nullptr == fGrContext) {
210 return false;
211 } else {
212 fGrContext->ref();
213 return true;
214 }
215 #endif
216 }
217
218 #if SK_SUPPORT_GPU
219 void setSampleCount(int sampleCount) {
220 fSampleCount = sampleCount;
221 }
222
223 void setUseDFText(bool useDFText) {
224 fUseDFText = useDFText;
225 }
226 #endif
227
228 void setDrawFilters(DrawFilterFlags const * const filters, const SkString& c onfigName) {
229 fHasDrawFilters = false;
230 fDrawFiltersConfig = configName;
231
232 for (size_t i = 0; i < SK_ARRAY_COUNT(fDrawFilters); ++i) {
233 fDrawFilters[i] = filters[i];
234 fHasDrawFilters |= SkToBool(filters[i]);
235 }
236 }
237
238 void setBBoxHierarchyType(BBoxHierarchyType bbhType) {
239 fBBoxHierarchyType = bbhType;
240 }
241
242 BBoxHierarchyType getBBoxHierarchyType() { return fBBoxHierarchyType; }
243
244 bool isUsingBitmapDevice() {
245 return kBitmap_DeviceType == fDeviceType;
246 }
247
248 virtual SkString getPerIterTimeFormat() { return SkString("%.2f"); }
249
250 virtual SkString getNormalTimeFormat() { return SkString("%6.2f"); }
251
252 /**
253 * Reports the configuration of this PictureRenderer.
254 */
255 SkString getConfigName() {
256 SkString config = this->getConfigNameInternal();
257 if (!fViewport.isEmpty()) {
258 config.appendf("_viewport_%ix%i", fViewport.width(), fViewport.heigh t());
259 }
260 if (fScaleFactor != SK_Scalar1) {
261 config.appendf("_scalar_%f", SkScalarToFloat(fScaleFactor));
262 }
263 if (kRTree_BBoxHierarchyType == fBBoxHierarchyType) {
264 config.append("_rtree");
265 }
266 #if SK_SUPPORT_GPU
267 switch (fDeviceType) {
268 case kGPU_DeviceType:
269 if (fSampleCount) {
270 config.appendf("_msaa%d", fSampleCount);
271 } else if (fUseDFText) {
272 config.append("_gpudft");
273 } else {
274 config.append("_gpu");
275 }
276 break;
277 case kNVPR_DeviceType:
278 config.appendf("_nvprmsaa%d", fSampleCount);
279 break;
280 #if SK_ANGLE
281 case kAngle_DeviceType:
282 config.append("_angle");
283 break;
284 #endif
285 #if SK_COMMAND_BUFFER
286 case kCommandBuffer_DeviceType:
287 config.append("_commandbuffer");
288 break;
289 #endif
290 #if SK_MESA
291 case kMesa_DeviceType:
292 config.append("_mesa");
293 break;
294 #endif
295 default:
296 // Assume that no extra info means bitmap.
297 break;
298 }
299 #endif
300 config.append(fDrawFiltersConfig.c_str());
301 return config;
302 }
303
304 Json::Value getJSONConfig() {
305 Json::Value result;
306
307 result["mode"] = this->getConfigNameInternal().c_str();
308 result["scale"] = 1.0f;
309 if (SK_Scalar1 != fScaleFactor) {
310 result["scale"] = SkScalarToFloat(fScaleFactor);
311 }
312 if (kRTree_BBoxHierarchyType == fBBoxHierarchyType) {
313 result["bbh"] = "rtree";
314 }
315 #if SK_SUPPORT_GPU
316 SkString tmp;
317 switch (fDeviceType) {
318 case kGPU_DeviceType:
319 if (0 != fSampleCount) {
320 tmp = "msaa";
321 tmp.appendS32(fSampleCount);
322 result["config"] = tmp.c_str();
323 } else if (fUseDFText) {
324 result["config"] = "gpudft";
325 } else {
326 result["config"] = "gpu";
327 }
328 break;
329 case kNVPR_DeviceType:
330 tmp = "nvprmsaa";
331 tmp.appendS32(fSampleCount);
332 result["config"] = tmp.c_str();
333 break;
334 #if SK_ANGLE
335 case kAngle_DeviceType:
336 result["config"] = "angle";
337 break;
338 #endif
339 #if SK_COMMAND_BUFFER
340 case kCommandBuffer_DeviceType:
341 result["config"] = "commandbuffer";
342 break;
343 #endif
344 #if SK_MESA
345 case kMesa_DeviceType:
346 result["config"] = "mesa";
347 break;
348 #endif
349 default:
350 // Assume that no extra info means bitmap.
351 break;
352 }
353 #endif
354 return result;
355 }
356
357 #if SK_SUPPORT_GPU
358 bool isUsingGpuDevice() {
359 switch (fDeviceType) {
360 case kGPU_DeviceType:
361 case kNVPR_DeviceType:
362 // fall through
363 #if SK_ANGLE
364 case kAngle_DeviceType:
365 // fall through
366 #endif
367 #if SK_COMMAND_BUFFER
368 case kCommandBuffer_DeviceType:
369 // fall through
370 #endif
371 #if SK_MESA
372 case kMesa_DeviceType:
373 #endif
374 return true;
375 default:
376 return false;
377 }
378 }
379
380 SkGLContext* getGLContext() {
381 GrContextFactory::GLContextType glContextType
382 = GrContextFactory::kNull_GLContextType;
383 switch(fDeviceType) {
384 case kGPU_DeviceType:
385 glContextType = GrContextFactory::kNative_GLContextType;
386 break;
387 case kNVPR_DeviceType:
388 glContextType = GrContextFactory::kNVPR_GLContextType;
389 break;
390 #if SK_ANGLE
391 case kAngle_DeviceType:
392 glContextType = GrContextFactory::kANGLE_GLContextType;
393 break;
394 #endif
395 #if SK_COMMAND_BUFFER
396 case kCommandBuffer_DeviceType:
397 glContextType = GrContextFactory::kCommandBuffer_GLContextType;
398 break;
399 #endif
400 #if SK_MESA
401 case kMesa_DeviceType:
402 glContextType = GrContextFactory::kMESA_GLContextType;
403 break;
404 #endif
405 default:
406 return nullptr;
407 }
408 return fGrContextFactory.getGLContext(glContextType);
409 }
410
411 GrContext* getGrContext() {
412 return fGrContext;
413 }
414
415 const GrContextOptions& getGrContextOptions() {
416 return fGrContextFactory.getGlobalOptions();
417 }
418 #endif
419
420 SkCanvas* getCanvas() {
421 return fCanvas;
422 }
423
424 const SkPicture* getPicture() {
425 return fPicture;
426 }
427
428 #if SK_SUPPORT_GPU
429 explicit PictureRenderer(const GrContextOptions &opts)
430 #else
431 PictureRenderer()
432 #endif
433 : fDeviceType(kBitmap_DeviceType)
434 , fBBoxHierarchyType(kNone_BBoxHierarchyType)
435 , fHasDrawFilters(false)
436 , fScaleFactor(SK_Scalar1)
437 #if SK_SUPPORT_GPU
438 , fGrContextFactory(opts)
439 , fGrContext(nullptr)
440 , fSampleCount(0)
441 , fUseDFText(false)
442 #endif
443 {
444 sk_bzero(fDrawFilters, sizeof(fDrawFilters));
445 fViewport.set(0, 0);
446 }
447
448 #if SK_SUPPORT_GPU
449 virtual ~PictureRenderer() {
450 SkSafeUnref(fGrContext);
451 }
452 #endif
453
454 protected:
455 SkAutoTUnref<SkCanvas> fCanvas;
456 SkAutoTUnref<const SkPicture> fPicture;
457 bool fUseChecksumBasedFilenames;
458 bool fUseMultiPictureDraw;
459 SkDeviceTypes fDeviceType;
460 BBoxHierarchyType fBBoxHierarchyType;
461 bool fHasDrawFilters;
462 DrawFilterFlags fDrawFilters[SkDrawFilter::kTypeCount];
463 SkString fDrawFiltersConfig;
464 SkString fWritePath;
465 SkString fMismatchPath;
466 SkString fInputFilename;
467
468 void buildBBoxHierarchy();
469
470 /**
471 * Return the total width that should be drawn. If the viewport width has be en set greater than
472 * 0, this will be the minimum of the current SkPicture's width and the view port's width.
473 */
474 int getViewWidth();
475
476 /**
477 * Return the total height that should be drawn. If the viewport height has been set greater
478 * than 0, this will be the minimum of the current SkPicture's height and th e viewport's height.
479 */
480 int getViewHeight();
481
482 /**
483 * Scales the provided canvas to the scale factor set by setScaleFactor.
484 */
485 void scaleToScaleFactor(SkCanvas*);
486
487 SkBBHFactory* getFactory();
488 uint32_t recordFlags() const { return 0; }
489 SkCanvas* setupCanvas();
490 virtual SkCanvas* setupCanvas(int width, int height);
491
492 /**
493 * Copy src to dest; if src==nullptr, set dest to empty string.
494 */
495 static void CopyString(SkString* dest, const SkString* src);
496
497 private:
498 SkISize fViewport;
499 SkScalar fScaleFactor;
500 #if SK_SUPPORT_GPU
501 GrContextFactory fGrContextFactory;
502 GrContext* fGrContext;
503 int fSampleCount;
504 bool fUseDFText;
505 #endif
506
507 virtual SkString getConfigNameInternal() = 0;
508
509 typedef SkRefCnt INHERITED;
510 };
511
512 /**
513 * This class does not do any rendering, but its render function executes record ing, which we want
514 * to time.
515 */
516 class RecordPictureRenderer : public PictureRenderer {
517 public:
518 #if SK_SUPPORT_GPU
519 RecordPictureRenderer(const GrContextOptions &opts) : INHERITED(opts) { }
520 #endif
521
522 bool render(SkBitmap** out = nullptr) override;
523
524 SkString getPerIterTimeFormat() override { return SkString("%.4f"); }
525
526 SkString getNormalTimeFormat() override { return SkString("%6.4f"); }
527
528 protected:
529 SkCanvas* setupCanvas(int width, int height) override;
530
531 private:
532 SkString getConfigNameInternal() override;
533
534 typedef PictureRenderer INHERITED;
535 };
536
537 class PipePictureRenderer : public PictureRenderer {
538 public:
539 #if SK_SUPPORT_GPU
540 PipePictureRenderer(const GrContextOptions &opts) : INHERITED(opts) { }
541 #endif
542
543 bool render(SkBitmap** out = nullptr) override;
544
545 private:
546 SkString getConfigNameInternal() override;
547
548 typedef PictureRenderer INHERITED;
549 };
550
551 class SimplePictureRenderer : public PictureRenderer {
552 public:
553 #if SK_SUPPORT_GPU
554 SimplePictureRenderer(const GrContextOptions &opts) : INHERITED(opts) { }
555 #endif
556
557 virtual void init(const SkPicture* pict,
558 const SkString* writePath,
559 const SkString* mismatchPath,
560 const SkString* inputFilename,
561 bool useChecksumBasedFilenames,
562 bool useMultiPictureDraw) override;
563
564 bool render(SkBitmap** out = nullptr) override;
565
566 private:
567 SkString getConfigNameInternal() override;
568
569 typedef PictureRenderer INHERITED;
570 };
571
572 class TiledPictureRenderer : public PictureRenderer {
573 public:
574 #if SK_SUPPORT_GPU
575 TiledPictureRenderer(const GrContextOptions &opts);
576 #else
577 TiledPictureRenderer();
578 #endif
579
580 virtual void init(const SkPicture* pict,
581 const SkString* writePath,
582 const SkString* mismatchPath,
583 const SkString* inputFilename,
584 bool useChecksumBasedFilenames,
585 bool useMultiPictureDraw) override;
586
587 /**
588 * Renders to tiles, rather than a single canvas.
589 * If fWritePath was provided, a separate file is
590 * created for each tile, named "path0.png", "path1.png", etc.
591 */
592 bool render(SkBitmap** out = nullptr) override;
593
594 void end() override;
595
596 void setTileWidth(int width) {
597 fTileWidth = width;
598 }
599
600 int getTileWidth() const {
601 return fTileWidth;
602 }
603
604 void setTileHeight(int height) {
605 fTileHeight = height;
606 }
607
608 int getTileHeight() const {
609 return fTileHeight;
610 }
611
612 void setTileWidthPercentage(double percentage) {
613 fTileWidthPercentage = percentage;
614 }
615
616 double getTileWidthPercentage() const {
617 return fTileWidthPercentage;
618 }
619
620 void setTileHeightPercentage(double percentage) {
621 fTileHeightPercentage = percentage;
622 }
623
624 double getTileHeightPercentage() const {
625 return fTileHeightPercentage;
626 }
627
628 void setTileMinPowerOf2Width(int width) {
629 SkASSERT(SkIsPow2(width) && width > 0);
630 if (!SkIsPow2(width) || width <= 0) {
631 return;
632 }
633
634 fTileMinPowerOf2Width = width;
635 }
636
637 int getTileMinPowerOf2Width() const {
638 return fTileMinPowerOf2Width;
639 }
640
641 TiledPictureRenderer* getTiledRenderer() override { return this; }
642
643 virtual bool supportsTimingIndividualTiles() { return true; }
644
645 /**
646 * Report the number of tiles in the x and y directions. Must not be called before init.
647 * @param x Output parameter identifying the number of tiles in the x direct ion.
648 * @param y Output parameter identifying the number of tiles in the y direct ion.
649 * @return True if the tiles have been set up, and x and y are meaningful. I f false, x and y are
650 * unmodified.
651 */
652 bool tileDimensions(int& x, int&y);
653
654 /**
655 * Move to the next tile and return its indices. Must be called before calli ng drawCurrentTile
656 * for the first time.
657 * @param i Output parameter identifying the column of the next tile to be d rawn on the next
658 * call to drawNextTile.
659 * @param j Output parameter identifying the row of the next tile to be dra wn on the next call
660 * to drawNextTile.
661 * @param True if the tiles have been created and the next tile to be drawn by drawCurrentTile
662 * is within the range of tiles. If false, i and j are unmodified.
663 */
664 bool nextTile(int& i, int& j);
665
666 /**
667 * Render one tile. This will draw the same tile each time it is called unti l nextTile is
668 * called. The tile rendered will depend on how many calls have been made to nextTile.
669 * It is an error to call this without first calling nextTile, or if nextTil e returns false.
670 */
671 void drawCurrentTile();
672
673 protected:
674 SkTDArray<SkIRect> fTileRects;
675
676 SkCanvas* setupCanvas(int width, int height) override;
677 SkString getConfigNameInternal() override;
678
679 private:
680 int fTileWidth;
681 int fTileHeight;
682 double fTileWidthPercentage;
683 double fTileHeightPercentage;
684 int fTileMinPowerOf2Width;
685
686 // These variables are only used for timing individual tiles.
687 // Next tile to draw in fTileRects.
688 int fCurrentTileOffset;
689 // Number of tiles in the x direction.
690 int fTilesX;
691 // Number of tiles in the y direction.
692 int fTilesY;
693
694 void setupTiles();
695 void setupPowerOf2Tiles();
696 bool postRender(SkCanvas*, const SkIRect& tileRect,
697 SkBitmap* tempBM, SkBitmap** out,
698 int tileNumber);
699
700 typedef PictureRenderer INHERITED;
701 };
702
703 /**
704 * This class does not do any rendering, but its render function executes turnin g an SkPictureRecord
705 * into an SkPicturePlayback, which we want to time.
706 */
707 class PlaybackCreationRenderer : public PictureRenderer {
708 public:
709 #if SK_SUPPORT_GPU
710 PlaybackCreationRenderer(const GrContextOptions &opts) : INHERITED(opts) { }
711 #endif
712
713 void setup() override;
714
715 bool render(SkBitmap** out = nullptr) override;
716
717 SkString getPerIterTimeFormat() override { return SkString("%.4f"); }
718
719 SkString getNormalTimeFormat() override { return SkString("%6.4f"); }
720
721 private:
722 SkAutoTDelete<SkPictureRecorder> fRecorder;
723
724 SkString getConfigNameInternal() override;
725
726 typedef PictureRenderer INHERITED;
727 };
728
729 #if SK_SUPPORT_GPU
730 extern PictureRenderer* CreateGatherPixelRefsRenderer(const GrContextOptions& op ts);
731 #else
732 extern PictureRenderer* CreateGatherPixelRefsRenderer();
733 #endif
734
735 }
736
737 #endif // PictureRenderer_DEFINED
OLDNEW
« no previous file with comments | « gyp/tools.gyp ('k') | tools/PictureRenderer.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698