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

Side by Side Diff: cc/tiles/software_image_decode_controller.cc

Issue 1801933004: Refactor SoftwareImageDecodeController (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Builds now. Created 4 years, 9 months 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 | « cc/tiles/software_image_decode_controller.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "cc/tiles/software_image_decode_controller.h" 5 #include "cc/tiles/software_image_decode_controller.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <functional> 9 #include <functional>
10 10
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 key.target_size().width() / static_cast<float>(key.src_rect().width()); 100 key.target_size().width() / static_cast<float>(key.src_rect().width());
101 float y_scale = 101 float y_scale =
102 key.target_size().height() / static_cast<float>(key.src_rect().height()); 102 key.target_size().height() / static_cast<float>(key.src_rect().height());
103 return SkSize::Make(x_scale, y_scale); 103 return SkSize::Make(x_scale, y_scale);
104 } 104 }
105 105
106 SkFilterQuality GetDecodedFilterQuality(const ImageDecodeControllerKey& key) { 106 SkFilterQuality GetDecodedFilterQuality(const ImageDecodeControllerKey& key) {
107 return std::min(key.filter_quality(), kLow_SkFilterQuality); 107 return std::min(key.filter_quality(), kLow_SkFilterQuality);
108 } 108 }
109 109
110 SkColorType SkColorTypeForDecoding(ResourceFormat format) {
vmpstr 2016/03/21 20:53:40 I think you kind of lost this patch in the merge?
cblume 2016/03/21 23:01:03 Whoops. Fixed.
111 // Use kN32_SkColorType if there is no corresponding SkColorType.
112 switch (format) {
113 case RGBA_4444:
114 return kARGB_4444_SkColorType;
115 case RGBA_8888:
116 case BGRA_8888:
117 return kN32_SkColorType;
118 case ALPHA_8:
119 return kAlpha_8_SkColorType;
120 case RGB_565:
121 return kRGB_565_SkColorType;
122 case LUMINANCE_8:
123 return kGray_8_SkColorType;
124 case ETC1:
125 case RED_8:
126 case LUMINANCE_F16:
127 return kN32_SkColorType;
128 }
129 NOTREACHED();
130 return kN32_SkColorType;
131 }
132
133 SkImageInfo CreateImageInfo(size_t width,
134 size_t height,
135 ResourceFormat format) {
136 return SkImageInfo::Make(width, height, SkColorTypeForDecoding(format),
137 kPremul_SkAlphaType);
138 }
139
140 } // namespace 110 } // namespace
141 111
142 SoftwareImageDecodeController::SoftwareImageDecodeController( 112 SoftwareImageDecodeController::SoftwareImageDecodeController(
143 ResourceFormat format) 113 ResourceFormat format)
144 : decoded_images_(ImageMRUCache::NO_AUTO_EVICT), 114 : decoded_images_(ImageMRUCache::NO_AUTO_EVICT),
145 at_raster_decoded_images_(ImageMRUCache::NO_AUTO_EVICT), 115 at_raster_decoded_images_(ImageMRUCache::NO_AUTO_EVICT),
146 locked_images_budget_(kLockedMemoryLimitBytes), 116 locked_images_budget_(kLockedMemoryLimitBytes),
147 format_(format) {} 117 format_(format) {}
148 118
149 SoftwareImageDecodeController::~SoftwareImageDecodeController() { 119 SoftwareImageDecodeController::~SoftwareImageDecodeController() {
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
358 if (decoded_images_ref_counts_.find(key) == 328 if (decoded_images_ref_counts_.find(key) ==
359 decoded_images_ref_counts_.end()) { 329 decoded_images_ref_counts_.end()) {
360 decoded_image->Unlock(); 330 decoded_image->Unlock();
361 } 331 }
362 332
363 decoded_images_.Put(key, std::move(decoded_image)); 333 decoded_images_.Put(key, std::move(decoded_image));
364 SanityCheckState(__LINE__, true); 334 SanityCheckState(__LINE__, true);
365 } 335 }
366 336
367 scoped_ptr<SoftwareImageDecodeController::DecodedImage> 337 scoped_ptr<SoftwareImageDecodeController::DecodedImage>
338 SoftwareImageDecodeController::DecodeImageNoneLowQuality(const ImageKey& key,
vmpstr 2016/03/21 20:53:40 Maybe we can just skip this function and use GetOr
cblume 2016/03/21 23:01:04 Done.
339 const SkImage& image) {
340 DCHECK(key.can_use_original_decode());
341
342 return AttemptToUseOriginalImage(key, image);
343 }
344
345 scoped_ptr<SoftwareImageDecodeController::DecodedImage>
346 SoftwareImageDecodeController::DecodeImageMediumQuality(const ImageKey& key,
347 const SkImage& image) {
348 NOTIMPLEMENTED();
349 return nullptr;
350 }
351
352 scoped_ptr<SoftwareImageDecodeController::DecodedImage>
353 SoftwareImageDecodeController::DecodeImageHighQuality(const ImageKey& key,
354 const SkImage& image) {
355 // If we get here, that means we couldn't use the original sized decode for
356 // whatever reason. However, in all cases we do need an original decode to
357 // either do a scale or to extract a subrect from the image.
358 auto decoded_image_result = DecodeImageOrUseCache(key, image);
359 if (!decoded_image_result.decoded_pixmap_.addr()) {
vmpstr 2016/03/21 20:53:40 nit: Usually for single line if and a single line
cblume 2016/03/21 23:01:04 Done.
360 return nullptr;
361 }
362
363
364 // Now we have a decoded_pixmap which represents the src_rect at the
365 // original scale. All we need to do is scale it.
366 return ScaleImage(key, decoded_image_result);
367 }
368
369 scoped_ptr<SoftwareImageDecodeController::DecodedImage>
368 SoftwareImageDecodeController::DecodeImageInternal( 370 SoftwareImageDecodeController::DecodeImageInternal(
369 const ImageKey& key, 371 const ImageKey& key,
370 const DrawImage& draw_image) { 372 const DrawImage& draw_image) {
371 TRACE_EVENT1("disabled-by-default-cc.debug", 373 TRACE_EVENT1("disabled-by-default-cc.debug",
372 "SoftwareImageDecodeController::DecodeImageInternal", "key", 374 "SoftwareImageDecodeController::DecodeImageInternal", "key",
373 key.ToString()); 375 key.ToString());
374 const SkImage* image = draw_image.image(); 376 const SkImage* image = draw_image.image();
375 377 if (!image) {
376 // If we can use the original decode, then we don't need to do scaling. We can
377 // just read pixels into the final memory.
378 if (key.can_use_original_decode()) {
379 SkImageInfo decoded_info =
380 CreateImageInfo(image->width(), image->height(), format_);
381 scoped_ptr<base::DiscardableMemory> decoded_pixels;
382 {
383 TRACE_EVENT0(
384 "disabled-by-default-cc.debug",
385 "SoftwareImageDecodeController::DecodeImageInternal - allocate "
386 "decoded pixels");
387 decoded_pixels =
388 base::DiscardableMemoryAllocator::GetInstance()
389 ->AllocateLockedDiscardableMemory(decoded_info.minRowBytes() *
390 decoded_info.height());
391 }
392 {
393 TRACE_EVENT0(
394 "disabled-by-default-cc.debug",
395 "SoftwareImageDecodeController::DecodeImageInternal - read pixels");
396 bool result = image->readPixels(decoded_info, decoded_pixels->data(),
397 decoded_info.minRowBytes(), 0, 0,
398 SkImage::kDisallow_CachingHint);
399
400 if (!result) {
401 decoded_pixels->Unlock();
402 return nullptr;
403 }
404 }
405
406 return make_scoped_ptr(new DecodedImage(
407 decoded_info, std::move(decoded_pixels), SkSize::Make(0, 0)));
408 }
409
410 // If we get here, that means we couldn't use the original sized decode for
411 // whatever reason. However, in all cases we do need an original decode to
412 // either do a scale or to extract a subrect from the image. So, what we can
413 // do is construct a key that would require a full sized decode, then get that
414 // decode via GetDecodedImageForDrawInternal(), use it, and unref it. This
415 // ensures that if the original sized decode is already available in any of
416 // the caches, we reuse that. We also ensure that all the proper locking takes
417 // place. If, on the other hand, the decode was not available,
418 // GetDecodedImageForDrawInternal() would decode the image, and unreffing it
419 // later ensures that we will store the discardable memory unlocked in the
420 // cache to be used by future requests.
421 gfx::Rect full_image_rect(image->width(), image->height());
422 DrawImage original_size_draw_image(image, gfx::RectToSkIRect(full_image_rect),
423 kNone_SkFilterQuality, SkMatrix::I());
424 ImageKey original_size_key =
425 ImageKey::FromDrawImage(original_size_draw_image);
426 // Sanity checks.
427 DCHECK(original_size_key.can_use_original_decode());
428 DCHECK(full_image_rect.size() == original_size_key.target_size());
429
430 auto decoded_draw_image = GetDecodedImageForDrawInternal(
431 original_size_key, original_size_draw_image);
432 if (!decoded_draw_image.image()) {
433 DrawWithImageFinished(original_size_draw_image, decoded_draw_image);
434 return nullptr; 378 return nullptr;
435 } 379 }
436 380
437 SkPixmap decoded_pixmap; 381 switch (key.filter_quality()) {
438 bool result = decoded_draw_image.image()->peekPixels(&decoded_pixmap); 382 case kNone_SkFilterQuality:
439 DCHECK(result); 383 // fall through
440 if (key.src_rect() != full_image_rect) { 384 case kLow_SkFilterQuality:
441 result = decoded_pixmap.extractSubset(&decoded_pixmap, 385 return DecodeImageNoneLowQuality(key, *image);
442 gfx::RectToSkIRect(key.src_rect())); 386 case kMedium_SkFilterQuality:
443 DCHECK(result); 387 return DecodeImageMediumQuality(key, *image);
388 case kHigh_SkFilterQuality:
389 return DecodeImageHighQuality(key, *image);
390 default:
391 NOTREACHED();
392 return nullptr;
444 } 393 }
445
446 // Now we have a decoded_pixmap which represents the src_rect at the
447 // original scale. All we need to do is scale it.
448 DCHECK(!key.target_size().IsEmpty());
449 SkImageInfo scaled_info = CreateImageInfo(
450 key.target_size().width(), key.target_size().height(), format_);
451 scoped_ptr<base::DiscardableMemory> scaled_pixels;
452 {
453 TRACE_EVENT0(
454 "disabled-by-default-cc.debug",
455 "SoftwareImageDecodeController::DecodeImageInternal - allocate "
456 "scaled pixels");
457 scaled_pixels = base::DiscardableMemoryAllocator::GetInstance()
458 ->AllocateLockedDiscardableMemory(
459 scaled_info.minRowBytes() * scaled_info.height());
460 }
461 SkPixmap scaled_pixmap(scaled_info, scaled_pixels->data(),
462 scaled_info.minRowBytes());
463 // TODO(vmpstr): Start handling more than just high filter quality.
464 DCHECK_EQ(kHigh_SkFilterQuality, key.filter_quality());
465 {
466 TRACE_EVENT0(
467 "disabled-by-default-cc.debug",
468 "SoftwareImageDecodeController::DecodeImageInternal - scale pixels");
469 bool result =
470 decoded_pixmap.scalePixels(scaled_pixmap, key.filter_quality());
471 DCHECK(result);
472 }
473
474 // Release the original sized decode. Any other intermediate result to release
475 // would be the subrect memory. However, that's in a scoped_ptr and will be
476 // deleted automatically when we return.
477 DrawWithImageFinished(original_size_draw_image, decoded_draw_image);
478
479 return make_scoped_ptr(
480 new DecodedImage(scaled_info, std::move(scaled_pixels),
481 SkSize::Make(-key.src_rect().x(), -key.src_rect().y())));
482 } 394 }
483 395
484 DecodedDrawImage SoftwareImageDecodeController::GetDecodedImageForDraw( 396 DecodedDrawImage SoftwareImageDecodeController::GetDecodedImageForDraw(
485 const DrawImage& draw_image) { 397 const DrawImage& draw_image) {
486 ImageKey key = ImageKey::FromDrawImage(draw_image); 398 ImageKey key = ImageKey::FromDrawImage(draw_image);
487 TRACE_EVENT1("disabled-by-default-cc.debug", 399 TRACE_EVENT1("disabled-by-default-cc.debug",
488 "SoftwareImageDecodeController::GetDecodedImageForDraw", "key", 400 "SoftwareImageDecodeController::GetDecodedImageForDraw", "key",
489 key.ToString()); 401 key.ToString());
490 // If the target size is empty, we can skip this image draw. 402 // If the target size is empty, we can skip this image draw.
491 if (key.target_size().IsEmpty()) 403 if (key.target_size().IsEmpty())
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 // Now we know that we don't have a locked image, and we seem to be the first 454 // Now we know that we don't have a locked image, and we seem to be the first
543 // thread encountering this image (that might not be true, since other threads 455 // thread encountering this image (that might not be true, since other threads
544 // might be decoding it already). This means that we need to decode the image 456 // might be decoding it already). This means that we need to decode the image
545 // assuming we can't lock the one we found in the cache. 457 // assuming we can't lock the one we found in the cache.
546 bool check_at_raster_cache = false; 458 bool check_at_raster_cache = false;
547 if (!decoded_image || !decoded_image->Lock()) { 459 if (!decoded_image || !decoded_image->Lock()) {
548 // Note that we have to release the lock, since this lock is also accessed 460 // Note that we have to release the lock, since this lock is also accessed
549 // on the compositor thread. This means holding on to the lock might stall 461 // on the compositor thread. This means holding on to the lock might stall
550 // the compositor thread for the duration of the decode! 462 // the compositor thread for the duration of the decode!
551 base::AutoUnlock unlock(lock_); 463 base::AutoUnlock unlock(lock_);
552 scoped_decoded_image = DecodeImageInternal(key, draw_image); 464 const SkImage* image = draw_image.image();
465 if (!image) {
vmpstr 2016/03/21 20:53:40 When would this be the case?
466 return DecodedDrawImage(nullptr, kNone_SkFilterQuality);
vmpstr 2016/03/21 20:53:40 If this is a case that we need to handle, then it
cblume 2016/03/21 23:01:03 I think you are right, this won't ever be the case
467 }
468 scoped_decoded_image = AttemptToUseOriginalImage(key, *image);
553 decoded_image = scoped_decoded_image.get(); 469 decoded_image = scoped_decoded_image.get();
554 470
555 // Skip the image if we couldn't decode it. 471 // Skip the image if we couldn't decode it.
556 if (!decoded_image) 472 if (!decoded_image)
557 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); 473 return DecodedDrawImage(nullptr, kNone_SkFilterQuality);
558 check_at_raster_cache = true; 474 check_at_raster_cache = true;
559 } 475 }
560 476
561 DCHECK(decoded_image == scoped_decoded_image.get()); 477 DCHECK(decoded_image == scoped_decoded_image.get());
562 478
(...skipping 20 matching lines...) Expand all
583 DCHECK(decoded_image->is_locked()); 499 DCHECK(decoded_image->is_locked());
584 RefAtRasterImage(key); 500 RefAtRasterImage(key);
585 SanityCheckState(__LINE__, true); 501 SanityCheckState(__LINE__, true);
586 auto decoded_draw_image = 502 auto decoded_draw_image =
587 DecodedDrawImage(decoded_image->image(), decoded_image->src_rect_offset(), 503 DecodedDrawImage(decoded_image->image(), decoded_image->src_rect_offset(),
588 GetScaleAdjustment(key), GetDecodedFilterQuality(key)); 504 GetScaleAdjustment(key), GetDecodedFilterQuality(key));
589 decoded_draw_image.set_at_raster_decode(true); 505 decoded_draw_image.set_at_raster_decode(true);
590 return decoded_draw_image; 506 return decoded_draw_image;
591 } 507 }
592 508
509 SoftwareImageDecodeController::DecodedImageResult::DecodedImageResult(
510 SkPixmap decoded_pixmap,
511 DrawImage original_size_draw_image,
512 DecodedDrawImage decoded_draw_image)
513 : decoded_pixmap_(decoded_pixmap),
514 original_size_draw_image_(original_size_draw_image),
515 decoded_draw_image_(decoded_draw_image) {}
516
517 scoped_ptr<SoftwareImageDecodeController::DecodedImage>
518 SoftwareImageDecodeController::AttemptToUseOriginalImage(const ImageKey& key,
vmpstr 2016/03/21 20:53:40 nit: Can we call this "GetOriginalImageDecode" or
cblume 2016/03/21 23:01:03 Done.
519 const SkImage& image) {
520 TRACE_EVENT1("disabled-by-default-cc.debug",
521 "SoftwareImageDecodeController::AttemptToUseOriginalImage",
522 "key", key.ToString());
523 if (!key.can_use_original_decode()) {
vmpstr 2016/03/21 20:53:40 Can we make this a DCHECK? Whatever code is callin
cblume 2016/03/21 23:01:04 Done.
524 return nullptr;
525 } else {
526 SkImageInfo decoded_info =
527 SkImageInfo::MakeN32Premul(image.width(), image.height());
528 scoped_ptr<base::DiscardableMemory> decoded_pixels;
529 {
530 TRACE_EVENT0("disabled-by-default-cc.debug",
531 "SoftwareImageDecodeController::AttemptToUseOriginalImage - "
532 "allocate decoded pixels");
533 decoded_pixels =
534 base::DiscardableMemoryAllocator::GetInstance()
535 ->AllocateLockedDiscardableMemory(decoded_info.minRowBytes() *
536 decoded_info.height());
537 }
538 {
539 TRACE_EVENT0("disabled-by-default-cc.debug",
540 "SoftwareImageDecodeController::AttemptToUseOriginalImage - "
541 "read pixels");
542 bool result = image.readPixels(decoded_info, decoded_pixels->data(),
543 decoded_info.minRowBytes(), 0, 0,
544 SkImage::kDisallow_CachingHint);
545
546 if (!result) {
547 decoded_pixels->Unlock();
548 return nullptr;
549 }
550 }
551
552 return make_scoped_ptr(new DecodedImage(
553 decoded_info, std::move(decoded_pixels), SkSize::Make(0, 0)));
554 }
555 }
556
557 SoftwareImageDecodeController::DecodedImageResult
558 SoftwareImageDecodeController::DecodeImageOrUseCache(const ImageKey& key,
559 const SkImage& image) {
560 // Construct a key to use in GetDecodedImageForDrawInternal().
561 // This allows us to reuse an image in any cache if available.
562 gfx::Rect full_image_rect(image.width(), image.height());
563 DrawImage original_size_draw_image(&image,
564 gfx::RectToSkIRect(full_image_rect),
565 kNone_SkFilterQuality, SkMatrix::I());
566 ImageKey original_size_key =
567 ImageKey::FromDrawImage(original_size_draw_image);
568 // Sanity checks.
569 DCHECK(original_size_key.can_use_original_decode());
570 DCHECK(full_image_rect.size() == original_size_key.target_size());
571
572 auto decoded_draw_image = GetDecodedImageForDrawInternal(
573 original_size_key, original_size_draw_image);
574
575 if (!decoded_draw_image.image()) {
576 DrawWithImageFinished(original_size_draw_image, decoded_draw_image);
577 return DecodedImageResult(SkPixmap(), DrawImage(),
578 DecodedDrawImage(nullptr, kNone_SkFilterQuality));
579 }
580
581 SkPixmap decoded_pixmap;
582 bool result = decoded_draw_image.image()->peekPixels(&decoded_pixmap);
583 DCHECK(result);
584 if (key.src_rect() != full_image_rect) {
585 result = decoded_pixmap.extractSubset(&decoded_pixmap,
586 gfx::RectToSkIRect(key.src_rect()));
587 DCHECK(result);
588 }
589
590 return DecodedImageResult(decoded_pixmap, original_size_draw_image,
591 decoded_draw_image);
592 }
593
594 scoped_ptr<SoftwareImageDecodeController::DecodedImage>
595 SoftwareImageDecodeController::ScaleImage(
596 const ImageKey& key,
597 const DecodedImageResult& decoded_image_result) {
598 DCHECK(!key.target_size().IsEmpty());
599 SkImageInfo scaled_info = SkImageInfo::MakeN32Premul(
600 key.target_size().width(), key.target_size().height());
601 scoped_ptr<base::DiscardableMemory> scaled_pixels;
602 {
603 TRACE_EVENT0(
604 "disabled-by-default-cc.debug",
605 "SoftwareImageDecodeController::ScaleImage - allocate scaled pixels");
606 scaled_pixels = base::DiscardableMemoryAllocator::GetInstance()
607 ->AllocateLockedDiscardableMemory(
608 scaled_info.minRowBytes() * scaled_info.height());
609 }
610 SkPixmap scaled_pixmap(scaled_info, scaled_pixels->data(),
611 scaled_info.minRowBytes());
612 // TODO(vmpstr): Start handling more than just high filter quality.
613 DCHECK_EQ(kHigh_SkFilterQuality, key.filter_quality());
614 {
615 TRACE_EVENT0("disabled-by-default-cc.debug",
616 "SoftwareImageDecodeController::ScaleImage - scale pixels");
617 bool result = decoded_image_result.decoded_pixmap_.scalePixels(
618 scaled_pixmap, key.filter_quality());
619 DCHECK(result);
620 }
621
622 // Release the original sized decode. Any other intermediate result to release
623 // would be the subrect memory. However, that's in a scoped_ptr and will be
624 // deleted automatically when we return.
625 DrawWithImageFinished(decoded_image_result.original_size_draw_image_,
626 decoded_image_result.decoded_draw_image_);
627
628 return make_scoped_ptr(new SoftwareImageDecodeController::DecodedImage(
629 scaled_info, std::move(scaled_pixels),
630 SkSize::Make(-key.src_rect().x(), -key.src_rect().y())));
631 }
632
593 void SoftwareImageDecodeController::DrawWithImageFinished( 633 void SoftwareImageDecodeController::DrawWithImageFinished(
594 const DrawImage& image, 634 const DrawImage& image,
595 const DecodedDrawImage& decoded_image) { 635 const DecodedDrawImage& decoded_image) {
596 TRACE_EVENT1("disabled-by-default-cc.debug", 636 TRACE_EVENT1("disabled-by-default-cc.debug",
597 "SoftwareImageDecodeController::DrawWithImageFinished", "key", 637 "SoftwareImageDecodeController::DrawWithImageFinished", "key",
598 ImageKey::FromDrawImage(image).ToString()); 638 ImageKey::FromDrawImage(image).ToString());
599 ImageKey key = ImageKey::FromDrawImage(image); 639 ImageKey key = ImageKey::FromDrawImage(image);
600 if (!decoded_image.image() || !CanHandleImage(key)) 640 if (!decoded_image.image() || !CanHandleImage(key))
601 return; 641 return;
602 642
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after
884 void SoftwareImageDecodeController::MemoryBudget::ResetUsage() { 924 void SoftwareImageDecodeController::MemoryBudget::ResetUsage() {
885 current_usage_bytes_ = 0; 925 current_usage_bytes_ = 0;
886 } 926 }
887 927
888 size_t SoftwareImageDecodeController::MemoryBudget::GetCurrentUsageSafe() 928 size_t SoftwareImageDecodeController::MemoryBudget::GetCurrentUsageSafe()
889 const { 929 const {
890 return current_usage_bytes_.ValueOrDie(); 930 return current_usage_bytes_.ValueOrDie();
891 } 931 }
892 932
893 } // namespace cc 933 } // namespace cc
OLDNEW
« no previous file with comments | « cc/tiles/software_image_decode_controller.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698