Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 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/output/render_surface_filters.h" | 5 #include "cc/output/render_surface_filters.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "cc/output/filter_operation.h" | 10 #include "cc/output/filter_operation.h" |
| 11 #include "cc/output/filter_operations.h" | 11 #include "cc/output/filter_operations.h" |
| 12 #include "skia/ext/refptr.h" | 12 #include "skia/ext/refptr.h" |
| 13 #include "third_party/skia/include/core/SkCanvas.h" | 13 #include "third_party/skia/include/core/SkCanvas.h" |
| 14 #include "third_party/skia/include/core/SkFlattenableBuffers.h" | |
| 15 #include "third_party/skia/include/core/SkImageFilter.h" | |
| 14 #include "third_party/skia/include/effects/SkBlurImageFilter.h" | 16 #include "third_party/skia/include/effects/SkBlurImageFilter.h" |
| 17 #include "third_party/skia/include/effects/SkColorFilterImageFilter.h" | |
| 15 #include "third_party/skia/include/effects/SkColorMatrixFilter.h" | 18 #include "third_party/skia/include/effects/SkColorMatrixFilter.h" |
| 16 #include "third_party/skia/include/effects/SkMagnifierImageFilter.h" | 19 #include "third_party/skia/include/effects/SkMagnifierImageFilter.h" |
| 20 #include "third_party/skia/include/effects/SkTestImageFilters.h" | |
|
ajuma
2013/07/31 18:40:37
This is for SkComposeImageFilter, used to connect
Stephen White
2013/07/31 19:18:51
Yes, I think it should be broken out into its own
ajuma
2013/09/09 17:35:36
Done.
| |
| 17 #include "third_party/skia/include/gpu/SkGpuDevice.h" | 21 #include "third_party/skia/include/gpu/SkGpuDevice.h" |
| 18 #include "third_party/skia/include/gpu/SkGrPixelRef.h" | 22 #include "third_party/skia/include/gpu/SkGrPixelRef.h" |
| 19 #include "ui/gfx/size_f.h" | 23 #include "ui/gfx/size_f.h" |
| 20 | 24 |
| 21 namespace cc { | 25 namespace cc { |
| 22 | 26 |
| 23 namespace { | 27 namespace { |
| 24 | 28 |
| 25 void GetBrightnessMatrix(float amount, SkScalar matrix[20]) { | 29 void GetBrightnessMatrix(float amount, SkScalar matrix[20]) { |
| 26 // Spec implementation | 30 // Spec implementation |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 224 } | 228 } |
| 225 case FilterOperation::COLOR_MATRIX: { | 229 case FilterOperation::COLOR_MATRIX: { |
| 226 memcpy(matrix, op.matrix(), sizeof(SkScalar[20])); | 230 memcpy(matrix, op.matrix(), sizeof(SkScalar[20])); |
| 227 return true; | 231 return true; |
| 228 } | 232 } |
| 229 default: | 233 default: |
| 230 return false; | 234 return false; |
| 231 } | 235 } |
| 232 } | 236 } |
| 233 | 237 |
| 238 skia::RefPtr<SkImageFilter> CreateMatrixImageFilter( | |
| 239 const SkScalar matrix[20], | |
| 240 skia::RefPtr<SkImageFilter> input) { | |
| 241 skia::RefPtr<SkColorFilter> color_filter = | |
| 242 skia::AdoptRef(new SkColorMatrixFilter(matrix)); | |
| 243 return skia::AdoptRef( | |
| 244 SkColorFilterImageFilter::Create(color_filter.get(), input.get())); | |
| 245 } | |
| 246 | |
| 234 class FilterBufferState { | 247 class FilterBufferState { |
| 235 public: | 248 public: |
| 236 FilterBufferState(GrContext* gr_context, | 249 FilterBufferState(GrContext* gr_context, |
| 237 gfx::SizeF size, | 250 gfx::SizeF size, |
| 238 unsigned texture_id) | 251 unsigned texture_id) |
| 239 : gr_context_(gr_context), | 252 : gr_context_(gr_context), |
| 240 current_texture_(0) { | 253 current_texture_(0) { |
| 241 // Wrap the source texture in a Ganesh platform texture. | 254 // Wrap the source texture in a Ganesh platform texture. |
| 242 GrBackendTextureDesc backend_texture_description; | 255 GrBackendTextureDesc backend_texture_description; |
| 243 backend_texture_description.fWidth = size.width(); | 256 backend_texture_description.fWidth = size.width(); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 302 } | 315 } |
| 303 | 316 |
| 304 GrContext* gr_context_; | 317 GrContext* gr_context_; |
| 305 SkBitmap source_; | 318 SkBitmap source_; |
| 306 skia::RefPtr<GrTexture> scratch_textures_[2]; | 319 skia::RefPtr<GrTexture> scratch_textures_[2]; |
| 307 int current_texture_; | 320 int current_texture_; |
| 308 skia::RefPtr<SkGpuDevice> device_; | 321 skia::RefPtr<SkGpuDevice> device_; |
| 309 skia::RefPtr<SkCanvas> canvas_; | 322 skia::RefPtr<SkCanvas> canvas_; |
| 310 }; | 323 }; |
| 311 | 324 |
| 325 class DropShadowImageFilter : public SkImageFilter { | |
|
ajuma
2013/07/31 18:40:37
This is copied from Blink. SkiaImageFilterBuilder
ajuma
2013/09/09 17:35:36
This is no longer needed, since DropShadowImageFil
| |
| 326 public: | |
| 327 DropShadowImageFilter(SkScalar dx, | |
| 328 SkScalar dy, | |
| 329 SkScalar sigma, | |
| 330 SkColor color, | |
| 331 SkImageFilter* input) | |
| 332 : SkImageFilter(input), | |
| 333 dx_(dx), | |
| 334 dy_(dy), | |
| 335 sigma_(sigma), | |
| 336 color_(color) { } | |
| 337 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(DropShadowImageFilter) | |
| 338 | |
| 339 protected: | |
| 340 explicit DropShadowImageFilter(SkFlattenableReadBuffer& buffer) | |
| 341 : SkImageFilter(buffer) { | |
| 342 dx_ = buffer.readScalar(); | |
| 343 dy_ = buffer.readScalar(); | |
| 344 sigma_ = buffer.readScalar(); | |
| 345 color_ = buffer.readColor(); | |
| 346 } | |
| 347 | |
| 348 virtual void flatten(SkFlattenableWriteBuffer& buffer) const OVERRIDE { | |
| 349 buffer.writeScalar(dx_); | |
| 350 buffer.writeScalar(dy_); | |
| 351 buffer.writeScalar(sigma_); | |
| 352 buffer.writeColor(color_); | |
| 353 } | |
| 354 | |
| 355 virtual bool onFilterImage(Proxy* proxy, | |
| 356 const SkBitmap& source, | |
| 357 const SkMatrix& matrix, | |
| 358 SkBitmap* result, | |
| 359 SkIPoint* loc) OVERRIDE { | |
| 360 SkBitmap src = source; | |
| 361 if (getInput(0) && | |
| 362 !getInput(0)->filterImage(proxy, source, matrix, &src, loc)) | |
| 363 return false; | |
| 364 | |
| 365 skia::RefPtr<SkDevice> device = skia::AdoptRef( | |
| 366 proxy->createDevice(src.width(), src.height())); | |
| 367 SkCanvas canvas(device.get()); | |
| 368 | |
| 369 skia::RefPtr<SkImageFilter> blurFilter = skia::AdoptRef( | |
| 370 new SkBlurImageFilter(sigma_, sigma_)); | |
| 371 skia::RefPtr<SkColorFilter> colorFilter = skia::AdoptRef( | |
| 372 SkColorFilter::CreateModeFilter(color_, SkXfermode::kSrcIn_Mode)); | |
| 373 SkPaint paint; | |
| 374 paint.setImageFilter(blurFilter.get()); | |
| 375 paint.setColorFilter(colorFilter.get()); | |
| 376 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); | |
| 377 canvas.saveLayer(0, &paint); | |
|
Stephen White
2013/07/31 19:18:51
FYI, we can probably get rid of the saveLayer()/re
| |
| 378 canvas.drawBitmap(src, dx_, dy_); | |
|
ajuma
2013/07/31 18:40:37
The version of DropShadowImageFilter currently in
Stephen White
2013/07/31 19:18:51
Yeah, I think that was when we had TopDown texture
| |
| 379 canvas.restore(); | |
| 380 canvas.drawBitmap(src, 0, 0); | |
| 381 *result = device.get()->accessBitmap(false); | |
| 382 return true; | |
| 383 } | |
| 384 | |
| 385 private: | |
| 386 SkScalar dx_, dy_, sigma_; | |
| 387 SkColor color_; | |
| 388 }; | |
| 389 | |
| 312 } // namespace | 390 } // namespace |
| 313 | 391 |
| 314 FilterOperations RenderSurfaceFilters::Optimize( | 392 FilterOperations RenderSurfaceFilters::Optimize( |
| 315 const FilterOperations& filters) { | 393 const FilterOperations& filters) { |
| 316 FilterOperations new_list; | 394 FilterOperations new_list; |
| 317 | 395 |
| 318 SkScalar accumulated_color_matrix[20]; | 396 SkScalar accumulated_color_matrix[20]; |
| 319 bool have_accumulated_color_matrix = false; | 397 bool have_accumulated_color_matrix = false; |
| 320 for (unsigned i = 0; i < filters.size(); ++i) { | 398 for (unsigned i = 0; i < filters.size(); ++i) { |
| 321 const FilterOperation& op = filters.at(i); | 399 const FilterOperation& op = filters.at(i); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 348 accumulated_color_matrix)); | 426 accumulated_color_matrix)); |
| 349 } | 427 } |
| 350 have_accumulated_color_matrix = false; | 428 have_accumulated_color_matrix = false; |
| 351 | 429 |
| 352 switch (op.type()) { | 430 switch (op.type()) { |
| 353 case FilterOperation::BLUR: | 431 case FilterOperation::BLUR: |
| 354 case FilterOperation::DROP_SHADOW: | 432 case FilterOperation::DROP_SHADOW: |
| 355 case FilterOperation::ZOOM: | 433 case FilterOperation::ZOOM: |
| 356 new_list.Append(op); | 434 new_list.Append(op); |
| 357 break; | 435 break; |
| 436 case FilterOperation::REFERENCE: | |
| 437 // Not supported on this code path. | |
| 438 NOTREACHED(); | |
| 358 case FilterOperation::BRIGHTNESS: | 439 case FilterOperation::BRIGHTNESS: |
| 359 case FilterOperation::SATURATING_BRIGHTNESS: | 440 case FilterOperation::SATURATING_BRIGHTNESS: |
| 360 case FilterOperation::CONTRAST: | 441 case FilterOperation::CONTRAST: |
| 361 case FilterOperation::GRAYSCALE: | 442 case FilterOperation::GRAYSCALE: |
| 362 case FilterOperation::SEPIA: | 443 case FilterOperation::SEPIA: |
| 363 case FilterOperation::SATURATE: | 444 case FilterOperation::SATURATE: |
| 364 case FilterOperation::HUE_ROTATE: | 445 case FilterOperation::HUE_ROTATE: |
| 365 case FilterOperation::INVERT: | 446 case FilterOperation::INVERT: |
| 366 case FilterOperation::OPACITY: | 447 case FilterOperation::OPACITY: |
| 367 case FilterOperation::COLOR_MATRIX: | 448 case FilterOperation::COLOR_MATRIX: |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 435 (height - (height / op.amount())) / 2.f, | 516 (height - (height / op.amount())) / 2.f, |
| 436 width / op.amount(), | 517 width / op.amount(), |
| 437 height / op.amount()), | 518 height / op.amount()), |
| 438 op.zoom_inset())); | 519 op.zoom_inset())); |
| 439 paint.setImageFilter(zoom_filter.get()); | 520 paint.setImageFilter(zoom_filter.get()); |
| 440 canvas->saveLayer(NULL, &paint); | 521 canvas->saveLayer(NULL, &paint); |
| 441 canvas->drawBitmap(state.Source(), 0, 0); | 522 canvas->drawBitmap(state.Source(), 0, 0); |
| 442 canvas->restore(); | 523 canvas->restore(); |
| 443 break; | 524 break; |
| 444 } | 525 } |
| 526 case FilterOperation::REFERENCE: | |
| 445 case FilterOperation::BRIGHTNESS: | 527 case FilterOperation::BRIGHTNESS: |
| 446 case FilterOperation::SATURATING_BRIGHTNESS: | 528 case FilterOperation::SATURATING_BRIGHTNESS: |
| 447 case FilterOperation::CONTRAST: | 529 case FilterOperation::CONTRAST: |
| 448 case FilterOperation::GRAYSCALE: | 530 case FilterOperation::GRAYSCALE: |
| 449 case FilterOperation::SEPIA: | 531 case FilterOperation::SEPIA: |
| 450 case FilterOperation::SATURATE: | 532 case FilterOperation::SATURATE: |
| 451 case FilterOperation::HUE_ROTATE: | 533 case FilterOperation::HUE_ROTATE: |
| 452 case FilterOperation::INVERT: | 534 case FilterOperation::INVERT: |
| 453 case FilterOperation::OPACITY: | 535 case FilterOperation::OPACITY: |
| 454 NOTREACHED(); | 536 NOTREACHED(); |
| 455 break; | 537 break; |
| 456 } | 538 } |
| 457 state.Swap(); | 539 state.Swap(); |
| 458 } | 540 } |
| 459 return state.Source(); | 541 return state.Source(); |
| 460 } | 542 } |
| 461 | 543 |
| 544 skia::RefPtr<SkImageFilter> RenderSurfaceFilters::BuildImageFilter( | |
| 545 const FilterOperations& filters) { | |
| 546 skia::RefPtr<SkImageFilter> image_filter; | |
| 547 SkScalar matrix[20]; | |
| 548 for (size_t i = 0; i < filters.size(); ++i) { | |
| 549 const FilterOperation& op = filters.at(i); | |
| 550 switch (op.type()) { | |
| 551 case FilterOperation::GRAYSCALE: | |
| 552 GetGrayscaleMatrix(1 - op.amount(), matrix); | |
| 553 image_filter = CreateMatrixImageFilter(matrix, image_filter); | |
| 554 break; | |
| 555 case FilterOperation::SEPIA: | |
| 556 GetSepiaMatrix(1 - op.amount(), matrix); | |
| 557 image_filter = CreateMatrixImageFilter(matrix, image_filter); | |
| 558 break; | |
| 559 case FilterOperation::SATURATE: | |
| 560 GetSaturateMatrix(op.amount(), matrix); | |
| 561 image_filter = CreateMatrixImageFilter(matrix, image_filter); | |
| 562 break; | |
| 563 case FilterOperation::HUE_ROTATE: | |
| 564 GetHueRotateMatrix(op.amount(), matrix); | |
| 565 image_filter = CreateMatrixImageFilter(matrix, image_filter); | |
| 566 break; | |
| 567 case FilterOperation::INVERT: | |
| 568 GetInvertMatrix(op.amount(), matrix); | |
| 569 image_filter = CreateMatrixImageFilter(matrix, image_filter); | |
| 570 break; | |
| 571 case FilterOperation::OPACITY: | |
| 572 GetOpacityMatrix(op.amount(), matrix); | |
| 573 image_filter = CreateMatrixImageFilter(matrix, image_filter); | |
| 574 break; | |
| 575 case FilterOperation::BRIGHTNESS: | |
| 576 GetBrightnessMatrix(op.amount(), matrix); | |
| 577 image_filter = CreateMatrixImageFilter(matrix, image_filter); | |
| 578 break; | |
| 579 case FilterOperation::CONTRAST: | |
| 580 GetContrastMatrix(op.amount(), matrix); | |
| 581 image_filter = CreateMatrixImageFilter(matrix, image_filter); | |
| 582 break; | |
| 583 case FilterOperation::BLUR: | |
| 584 image_filter = skia::AdoptRef(new SkBlurImageFilter( | |
| 585 op.amount(), op.amount(), image_filter.get())); | |
| 586 break; | |
| 587 case FilterOperation::DROP_SHADOW: | |
| 588 image_filter = skia::AdoptRef(new DropShadowImageFilter( | |
| 589 SkIntToScalar(op.drop_shadow_offset().x()), | |
| 590 SkIntToScalar(op.drop_shadow_offset().y()), | |
| 591 SkIntToScalar(op.amount()), | |
| 592 op.drop_shadow_color(), | |
| 593 image_filter.get())); | |
| 594 break; | |
| 595 case FilterOperation::COLOR_MATRIX: | |
| 596 image_filter = CreateMatrixImageFilter(op.matrix(), image_filter); | |
| 597 break; | |
| 598 case FilterOperation::ZOOM: | |
| 599 // TODO(ajuma): Add support for this. Note that zoom filter operations | |
| 600 // are only used for background filters right now. | |
|
ajuma
2013/07/31 18:40:37
Is this worth doing? That is, are there any plans
Stephen White
2013/07/31 19:18:51
Check with zork@ about this filter; I think it's o
ajuma
2013/09/09 17:35:36
I've added the code that was missing here for ZOOM
| |
| 601 NOTREACHED(); | |
| 602 case FilterOperation::SATURATING_BRIGHTNESS: | |
| 603 GetSaturatingBrightnessMatrix(op.amount(), matrix); | |
| 604 image_filter = CreateMatrixImageFilter(matrix, image_filter); | |
| 605 break; | |
| 606 case FilterOperation::REFERENCE: { | |
| 607 skia::RefPtr<SkColorFilter> cf; | |
| 608 | |
| 609 { | |
| 610 SkColorFilter* colorfilter_rawptr = NULL; | |
| 611 op.image_filter()->asColorFilter(&colorfilter_rawptr); | |
| 612 cf = skia::AdoptRef(colorfilter_rawptr); | |
| 613 } | |
| 614 | |
| 615 if (cf && cf->asColorMatrix(matrix) && | |
| 616 !op.image_filter()->getInput(0)) { | |
| 617 image_filter = CreateMatrixImageFilter(matrix, image_filter); | |
| 618 } else if (image_filter.get()) { | |
| 619 image_filter = skia::AdoptRef(new SkComposeImageFilter( | |
| 620 op.image_filter().get(), image_filter.get())); | |
|
ajuma
2013/07/31 18:40:37
The plan is to use a no-op filter as the SourceGra
Stephen White
2013/07/31 19:18:51
That seems reasonable. I like the use of the SkCom
| |
| 621 } else { | |
| 622 image_filter = op.image_filter(); | |
| 623 } | |
| 624 break; | |
| 625 } | |
| 626 } | |
| 627 } | |
| 628 return image_filter; | |
| 629 } | |
| 630 | |
| 462 } // namespace cc | 631 } // namespace cc |
| OLD | NEW |