OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc.
All rights reserved. | 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. |
| 3 * All rights reserved. |
3 * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies) | 4 * Copyright (C) 2008, 2010 Nokia Corporation and/or its subsidiary(-ies) |
4 * Copyright (C) 2007 Alp Toker <alp@atoker.com> | 5 * Copyright (C) 2007 Alp Toker <alp@atoker.com> |
5 * Copyright (C) 2008 Eric Seidel <eric@webkit.org> | 6 * Copyright (C) 2008 Eric Seidel <eric@webkit.org> |
6 * Copyright (C) 2008 Dirk Schulze <krit@webkit.org> | 7 * Copyright (C) 2008 Dirk Schulze <krit@webkit.org> |
7 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. | 8 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. |
8 * Copyright (C) 2012, 2013 Intel Corporation. All rights reserved. | 9 * Copyright (C) 2012, 2013 Intel Corporation. All rights reserved. |
9 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. | 10 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. |
10 * | 11 * |
11 * Redistribution and use in source and binary forms, with or without | 12 * Redistribution and use in source and binary forms, with or without |
12 * modification, are permitted provided that the following conditions | 13 * modification, are permitted provided that the following conditions |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 static const char rtl[] = "rtl"; | 74 static const char rtl[] = "rtl"; |
74 static const char ltr[] = "ltr"; | 75 static const char ltr[] = "ltr"; |
75 static const double TryRestoreContextInterval = 0.5; | 76 static const double TryRestoreContextInterval = 0.5; |
76 static const unsigned MaxTryRestoreContextAttempts = 4; | 77 static const unsigned MaxTryRestoreContextAttempts = 4; |
77 static const double cDeviceScaleFactor = 1.0; // Canvas is device independent | 78 static const double cDeviceScaleFactor = 1.0; // Canvas is device independent |
78 | 79 |
79 static bool contextLostRestoredEventsEnabled() { | 80 static bool contextLostRestoredEventsEnabled() { |
80 return RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled(); | 81 return RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled(); |
81 } | 82 } |
82 | 83 |
83 // Drawing methods need to use this instead of SkAutoCanvasRestore in case overd
raw | 84 // Drawing methods need to use this instead of SkAutoCanvasRestore in case |
84 // detection substitutes the recording canvas (to discard overdrawn draw calls). | 85 // overdraw detection substitutes the recording canvas (to discard overdrawn |
| 86 // draw calls). |
85 class CanvasRenderingContext2DAutoRestoreSkCanvas { | 87 class CanvasRenderingContext2DAutoRestoreSkCanvas { |
86 STACK_ALLOCATED(); | 88 STACK_ALLOCATED(); |
87 | 89 |
88 public: | 90 public: |
89 explicit CanvasRenderingContext2DAutoRestoreSkCanvas( | 91 explicit CanvasRenderingContext2DAutoRestoreSkCanvas( |
90 CanvasRenderingContext2D* context) | 92 CanvasRenderingContext2D* context) |
91 : m_context(context), m_saveCount(0) { | 93 : m_context(context), m_saveCount(0) { |
92 ASSERT(m_context); | 94 ASSERT(m_context); |
93 SkCanvas* c = m_context->drawingCanvas(); | 95 SkCanvas* c = m_context->drawingCanvas(); |
94 if (c) { | 96 if (c) { |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
221 | 223 |
222 void CanvasRenderingContext2D::dispatchContextLostEvent(TimerBase*) { | 224 void CanvasRenderingContext2D::dispatchContextLostEvent(TimerBase*) { |
223 if (canvas() && contextLostRestoredEventsEnabled()) { | 225 if (canvas() && contextLostRestoredEventsEnabled()) { |
224 Event* event = Event::createCancelable(EventTypeNames::contextlost); | 226 Event* event = Event::createCancelable(EventTypeNames::contextlost); |
225 canvas()->dispatchEvent(event); | 227 canvas()->dispatchEvent(event); |
226 if (event->defaultPrevented()) { | 228 if (event->defaultPrevented()) { |
227 m_contextRestorable = false; | 229 m_contextRestorable = false; |
228 } | 230 } |
229 } | 231 } |
230 | 232 |
231 // If RealLostContext, it means the context was not lost due to surface failur
e | 233 // If RealLostContext, it means the context was not lost due to surface |
232 // but rather due to a an eviction, which means image buffer exists. | 234 // failure but rather due to a an eviction, which means image buffer exists. |
233 if (m_contextRestorable && m_contextLostMode == RealLostContext) { | 235 if (m_contextRestorable && m_contextLostMode == RealLostContext) { |
234 m_tryRestoreContextAttemptCount = 0; | 236 m_tryRestoreContextAttemptCount = 0; |
235 m_tryRestoreContextEventTimer.startRepeating(TryRestoreContextInterval, | 237 m_tryRestoreContextEventTimer.startRepeating(TryRestoreContextInterval, |
236 BLINK_FROM_HERE); | 238 BLINK_FROM_HERE); |
237 } | 239 } |
238 } | 240 } |
239 | 241 |
240 void CanvasRenderingContext2D::tryRestoreContextEvent(TimerBase* timer) { | 242 void CanvasRenderingContext2D::tryRestoreContextEvent(TimerBase* timer) { |
241 if (m_contextLostMode == NotLostContext) { | 243 if (m_contextLostMode == NotLostContext) { |
242 // Canvas was already restored (possibly thanks to a resize), so stop trying
. | 244 // Canvas was already restored (possibly thanks to a resize), so stop |
| 245 // trying. |
243 m_tryRestoreContextEventTimer.stop(); | 246 m_tryRestoreContextEventTimer.stop(); |
244 return; | 247 return; |
245 } | 248 } |
246 | 249 |
247 DCHECK(m_contextLostMode == RealLostContext); | 250 DCHECK(m_contextLostMode == RealLostContext); |
248 if (canvas()->hasImageBuffer() && canvas()->buffer()->restoreSurface()) { | 251 if (canvas()->hasImageBuffer() && canvas()->buffer()->restoreSurface()) { |
249 m_tryRestoreContextEventTimer.stop(); | 252 m_tryRestoreContextEventTimer.stop(); |
250 dispatchContextRestoredEvent(nullptr); | 253 dispatchContextRestoredEvent(nullptr); |
251 } | 254 } |
252 | 255 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
323 | 326 |
324 // Offset by the canvas rect | 327 // Offset by the canvas rect |
325 LayoutRect pathRect(boundingRect); | 328 LayoutRect pathRect(boundingRect); |
326 IntRect canvasRect = layoutBox->absoluteContentBox(); | 329 IntRect canvasRect = layoutBox->absoluteContentBox(); |
327 pathRect.moveBy(canvasRect.location()); | 330 pathRect.moveBy(canvasRect.location()); |
328 | 331 |
329 renderer->scrollRectToVisible(pathRect, ScrollAlignment::alignCenterAlways, | 332 renderer->scrollRectToVisible(pathRect, ScrollAlignment::alignCenterAlways, |
330 ScrollAlignment::alignTopAlways); | 333 ScrollAlignment::alignTopAlways); |
331 | 334 |
332 // TODO: should implement "inform the user" that the caret and/or | 335 // TODO: should implement "inform the user" that the caret and/or |
333 // selection the specified rectangle of the canvas. See http://crbug.com/35798
7 | 336 // selection the specified rectangle of the canvas. See |
| 337 // http://crbug.com/357987 |
334 } | 338 } |
335 | 339 |
336 void CanvasRenderingContext2D::clearRect(double x, | 340 void CanvasRenderingContext2D::clearRect(double x, |
337 double y, | 341 double y, |
338 double width, | 342 double width, |
339 double height) { | 343 double height) { |
340 BaseRenderingContext2D::clearRect(x, y, width, height); | 344 BaseRenderingContext2D::clearRect(x, y, width, height); |
341 | 345 |
342 if (m_hitRegionManager) { | 346 if (m_hitRegionManager) { |
343 FloatRect rect(x, y, width, height); | 347 FloatRect rect(x, y, width, height); |
(...skipping 17 matching lines...) Expand all Loading... |
361 | 365 |
362 bool CanvasRenderingContext2D::stateHasFilter() { | 366 bool CanvasRenderingContext2D::stateHasFilter() { |
363 return state().hasFilter(canvas(), canvas()->size(), this); | 367 return state().hasFilter(canvas(), canvas()->size(), this); |
364 } | 368 } |
365 | 369 |
366 SkImageFilter* CanvasRenderingContext2D::stateGetFilter() { | 370 SkImageFilter* CanvasRenderingContext2D::stateGetFilter() { |
367 return state().getFilter(canvas(), canvas()->size(), this); | 371 return state().getFilter(canvas(), canvas()->size(), this); |
368 } | 372 } |
369 | 373 |
370 void CanvasRenderingContext2D::snapshotStateForFilter() { | 374 void CanvasRenderingContext2D::snapshotStateForFilter() { |
371 // The style resolution required for fonts is not available in frame-less docu
ments. | 375 // The style resolution required for fonts is not available in frame-less |
| 376 // documents. |
372 if (!canvas()->document().frame()) | 377 if (!canvas()->document().frame()) |
373 return; | 378 return; |
374 | 379 |
375 modifiableState().setFontForFilter(accessFont()); | 380 modifiableState().setFontForFilter(accessFont()); |
376 } | 381 } |
377 | 382 |
378 SkCanvas* CanvasRenderingContext2D::drawingCanvas() const { | 383 SkCanvas* CanvasRenderingContext2D::drawingCanvas() const { |
379 if (isContextLost()) | 384 if (isContextLost()) |
380 return nullptr; | 385 return nullptr; |
381 return canvas()->drawingCanvas(); | 386 return canvas()->drawingCanvas(); |
(...skipping 28 matching lines...) Expand all Loading... |
410 | 415 |
411 serializedFont.appendNumber(fontDescription.computedPixelSize()); | 416 serializedFont.appendNumber(fontDescription.computedPixelSize()); |
412 serializedFont.append("px"); | 417 serializedFont.append("px"); |
413 | 418 |
414 const FontFamily& firstFontFamily = fontDescription.family(); | 419 const FontFamily& firstFontFamily = fontDescription.family(); |
415 for (const FontFamily* fontFamily = &firstFontFamily; fontFamily; | 420 for (const FontFamily* fontFamily = &firstFontFamily; fontFamily; |
416 fontFamily = fontFamily->next()) { | 421 fontFamily = fontFamily->next()) { |
417 if (fontFamily != &firstFontFamily) | 422 if (fontFamily != &firstFontFamily) |
418 serializedFont.append(','); | 423 serializedFont.append(','); |
419 | 424 |
420 // FIXME: We should append family directly to serializedFont rather than bui
lding a temporary string. | 425 // FIXME: We should append family directly to serializedFont rather than |
| 426 // building a temporary string. |
421 String family = fontFamily->family(); | 427 String family = fontFamily->family(); |
422 if (family.startsWith("-webkit-")) | 428 if (family.startsWith("-webkit-")) |
423 family = family.substring(8); | 429 family = family.substring(8); |
424 if (family.contains(' ')) | 430 if (family.contains(' ')) |
425 family = "\"" + family + "\""; | 431 family = "\"" + family + "\""; |
426 | 432 |
427 serializedFont.append(' '); | 433 serializedFont.append(' '); |
428 serializedFont.append(family); | 434 serializedFont.append(family); |
429 } | 435 } |
430 | 436 |
431 return serializedFont.toString(); | 437 return serializedFont.toString(); |
432 } | 438 } |
433 | 439 |
434 void CanvasRenderingContext2D::setFont(const String& newFont) { | 440 void CanvasRenderingContext2D::setFont(const String& newFont) { |
435 // The style resolution required for fonts is not available in frame-less docu
ments. | 441 // The style resolution required for fonts is not available in frame-less |
| 442 // documents. |
436 if (!canvas()->document().frame()) | 443 if (!canvas()->document().frame()) |
437 return; | 444 return; |
438 | 445 |
439 canvas()->document().updateStyleAndLayoutTreeForNode(canvas()); | 446 canvas()->document().updateStyleAndLayoutTreeForNode(canvas()); |
440 | 447 |
441 // The following early exit is dependent on the cache not being empty | 448 // The following early exit is dependent on the cache not being empty |
442 // because an empty cache may indicate that a style change has occured | 449 // because an empty cache may indicate that a style change has occured |
443 // which would require that the font be re-resolved. This check has to | 450 // which would require that the font be re-resolved. This check has to |
444 // come after the layout tree update to flush pending style changes. | 451 // come after the layout tree update to flush pending style changes. |
445 if (newFont == state().unparsedFont() && state().hasRealizedFont() && | 452 if (newFont == state().unparsedFont() && state().hasRealizedFont() && |
446 m_fontsResolvedUsingCurrentStyle.size() > 0) | 453 m_fontsResolvedUsingCurrentStyle.size() > 0) |
447 return; | 454 return; |
448 | 455 |
449 CanvasFontCache* canvasFontCache = canvas()->document().canvasFontCache(); | 456 CanvasFontCache* canvasFontCache = canvas()->document().canvasFontCache(); |
450 | 457 |
451 // Map the <canvas> font into the text style. If the font uses keywords like l
arger/smaller, these will work | 458 // Map the <canvas> font into the text style. If the font uses keywords like |
452 // relative to the canvas. | 459 // larger/smaller, these will work relative to the canvas. |
453 RefPtr<ComputedStyle> fontStyle; | 460 RefPtr<ComputedStyle> fontStyle; |
454 const ComputedStyle* computedStyle = canvas()->ensureComputedStyle(); | 461 const ComputedStyle* computedStyle = canvas()->ensureComputedStyle(); |
455 if (computedStyle) { | 462 if (computedStyle) { |
456 HashMap<String, Font>::iterator i = | 463 HashMap<String, Font>::iterator i = |
457 m_fontsResolvedUsingCurrentStyle.find(newFont); | 464 m_fontsResolvedUsingCurrentStyle.find(newFont); |
458 if (i != m_fontsResolvedUsingCurrentStyle.end()) { | 465 if (i != m_fontsResolvedUsingCurrentStyle.end()) { |
459 ASSERT(m_fontLRUList.contains(newFont)); | 466 ASSERT(m_fontLRUList.contains(newFont)); |
460 m_fontLRUList.remove(newFont); | 467 m_fontLRUList.remove(newFont); |
461 m_fontLRUList.add(newFont); | 468 m_fontLRUList.add(newFont); |
462 modifiableState().setFont( | 469 modifiableState().setFont( |
463 i->value, canvas()->document().styleEngine().fontSelector()); | 470 i->value, canvas()->document().styleEngine().fontSelector()); |
464 } else { | 471 } else { |
465 MutableStylePropertySet* parsedStyle = | 472 MutableStylePropertySet* parsedStyle = |
466 canvasFontCache->parseFont(newFont); | 473 canvasFontCache->parseFont(newFont); |
467 if (!parsedStyle) | 474 if (!parsedStyle) |
468 return; | 475 return; |
469 fontStyle = ComputedStyle::create(); | 476 fontStyle = ComputedStyle::create(); |
470 FontDescription elementFontDescription( | 477 FontDescription elementFontDescription( |
471 computedStyle->getFontDescription()); | 478 computedStyle->getFontDescription()); |
472 // Reset the computed size to avoid inheriting the zoom factor from the <c
anvas> element. | 479 // Reset the computed size to avoid inheriting the zoom factor from the |
| 480 // <canvas> element. |
473 elementFontDescription.setComputedSize( | 481 elementFontDescription.setComputedSize( |
474 elementFontDescription.specifiedSize()); | 482 elementFontDescription.specifiedSize()); |
475 fontStyle->setFontDescription(elementFontDescription); | 483 fontStyle->setFontDescription(elementFontDescription); |
476 fontStyle->font().update(fontStyle->font().getFontSelector()); | 484 fontStyle->font().update(fontStyle->font().getFontSelector()); |
477 canvas()->document().ensureStyleResolver().computeFont(fontStyle.get(), | 485 canvas()->document().ensureStyleResolver().computeFont(fontStyle.get(), |
478 *parsedStyle); | 486 *parsedStyle); |
479 m_fontsResolvedUsingCurrentStyle.add(newFont, fontStyle->font()); | 487 m_fontsResolvedUsingCurrentStyle.add(newFont, fontStyle->font()); |
480 ASSERT(!m_fontLRUList.contains(newFont)); | 488 ASSERT(!m_fontLRUList.contains(newFont)); |
481 m_fontLRUList.add(newFont); | 489 m_fontLRUList.add(newFont); |
482 pruneLocalFontCache(canvasFontCache->hardMaxFonts()); // hard limit | 490 pruneLocalFontCache(canvasFontCache->hardMaxFonts()); // hard limit |
483 schedulePruneLocalFontCacheIfNeeded(); // soft limit | 491 schedulePruneLocalFontCacheIfNeeded(); // soft limit |
484 modifiableState().setFont( | 492 modifiableState().setFont( |
485 fontStyle->font(), canvas()->document().styleEngine().fontSelector()); | 493 fontStyle->font(), canvas()->document().styleEngine().fontSelector()); |
486 } | 494 } |
487 } else { | 495 } else { |
488 Font resolvedFont; | 496 Font resolvedFont; |
489 if (!canvasFontCache->getFontUsingDefaultStyle(newFont, resolvedFont)) | 497 if (!canvasFontCache->getFontUsingDefaultStyle(newFont, resolvedFont)) |
490 return; | 498 return; |
491 modifiableState().setFont( | 499 modifiableState().setFont( |
492 resolvedFont, canvas()->document().styleEngine().fontSelector()); | 500 resolvedFont, canvas()->document().styleEngine().fontSelector()); |
493 } | 501 } |
494 | 502 |
495 // The parse succeeded. | 503 // The parse succeeded. |
496 String newFontSafeCopy( | 504 String newFontSafeCopy(newFont); // Create a string copy since newFont can be |
497 newFont); // Create a string copy since newFont can be deleted inside rea
lizeSaves. | 505 // deleted inside realizeSaves. |
498 modifiableState().setUnparsedFont(newFontSafeCopy); | 506 modifiableState().setUnparsedFont(newFontSafeCopy); |
499 } | 507 } |
500 | 508 |
501 void CanvasRenderingContext2D::schedulePruneLocalFontCacheIfNeeded() { | 509 void CanvasRenderingContext2D::schedulePruneLocalFontCacheIfNeeded() { |
502 if (m_pruneLocalFontCacheScheduled) | 510 if (m_pruneLocalFontCacheScheduled) |
503 return; | 511 return; |
504 m_pruneLocalFontCacheScheduled = true; | 512 m_pruneLocalFontCacheScheduled = true; |
505 Platform::current()->currentThread()->addTaskObserver(this); | 513 Platform::current()->currentThread()->addTaskObserver(this); |
506 } | 514 } |
507 | 515 |
508 void CanvasRenderingContext2D::didProcessTask() { | 516 void CanvasRenderingContext2D::didProcessTask() { |
509 Platform::current()->currentThread()->removeTaskObserver(this); | 517 Platform::current()->currentThread()->removeTaskObserver(this); |
510 | 518 |
511 // This should be the only place where canvas() needs to be checked for nullne
ss | 519 // This should be the only place where canvas() needs to be checked for |
512 // because the circular refence with HTMLCanvasElement mean the canvas and the | 520 // nullness because the circular refence with HTMLCanvasElement mean the |
513 // context keep each other alive as long as the pair is referenced the task | 521 // canvas and the context keep each other alive as long as the pair is |
514 // observer is the only persisten refernce to this object that is not traced, | 522 // referenced the task observer is the only persisten refernce to this object |
515 // so didProcessTask() may be call at a time when the canvas has been garbage | 523 // that is not traced, so didProcessTask() may be call at a time when the |
516 // collected but not the context. | 524 // canvas has been garbage collected but not the context. |
517 if (!canvas()) | 525 if (!canvas()) |
518 return; | 526 return; |
519 | 527 |
520 // The rendering surface needs to be prepared now because it will be too late | 528 // The rendering surface needs to be prepared now because it will be too late |
521 // to create a layer once we are in the paint invalidation phase. | 529 // to create a layer once we are in the paint invalidation phase. |
522 canvas()->prepareSurfaceForPaintingIfNeeded(); | 530 canvas()->prepareSurfaceForPaintingIfNeeded(); |
523 | 531 |
524 pruneLocalFontCache(canvas()->document().canvasFontCache()->maxFonts()); | 532 pruneLocalFontCache(canvas()->document().canvasFontCache()->maxFonts()); |
525 m_pruneLocalFontCacheScheduled = false; | 533 m_pruneLocalFontCacheScheduled = false; |
526 } | 534 } |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
719 double y, | 727 double y, |
720 double maxWidth) { | 728 double maxWidth) { |
721 trackDrawCall(StrokeText); | 729 trackDrawCall(StrokeText); |
722 drawTextInternal(text, x, y, CanvasRenderingContext2DState::StrokePaintType, | 730 drawTextInternal(text, x, y, CanvasRenderingContext2DState::StrokePaintType, |
723 &maxWidth); | 731 &maxWidth); |
724 } | 732 } |
725 | 733 |
726 TextMetrics* CanvasRenderingContext2D::measureText(const String& text) { | 734 TextMetrics* CanvasRenderingContext2D::measureText(const String& text) { |
727 TextMetrics* metrics = TextMetrics::create(); | 735 TextMetrics* metrics = TextMetrics::create(); |
728 | 736 |
729 // The style resolution required for fonts is not available in frame-less docu
ments. | 737 // The style resolution required for fonts is not available in frame-less |
| 738 // documents. |
730 if (!canvas()->document().frame()) | 739 if (!canvas()->document().frame()) |
731 return metrics; | 740 return metrics; |
732 | 741 |
733 canvas()->document().updateStyleAndLayoutTreeForNode(canvas()); | 742 canvas()->document().updateStyleAndLayoutTreeForNode(canvas()); |
734 const Font& font = accessFont(); | 743 const Font& font = accessFont(); |
735 | 744 |
736 TextDirection direction; | 745 TextDirection direction; |
737 if (state().getDirection() == CanvasRenderingContext2DState::DirectionInherit) | 746 if (state().getDirection() == CanvasRenderingContext2DState::DirectionInherit) |
738 direction = determineDirectionality(text); | 747 direction = determineDirectionality(text); |
739 else | 748 else |
(...skipping 15 matching lines...) Expand all Loading... |
755 const FontMetrics& fontMetrics = font.getFontMetrics(); | 764 const FontMetrics& fontMetrics = font.getFontMetrics(); |
756 const float ascent = fontMetrics.floatAscent(); | 765 const float ascent = fontMetrics.floatAscent(); |
757 const float descent = fontMetrics.floatDescent(); | 766 const float descent = fontMetrics.floatDescent(); |
758 const float baselineY = getFontBaseline(fontMetrics); | 767 const float baselineY = getFontBaseline(fontMetrics); |
759 | 768 |
760 metrics->setFontBoundingBoxAscent(ascent - baselineY); | 769 metrics->setFontBoundingBoxAscent(ascent - baselineY); |
761 metrics->setFontBoundingBoxDescent(descent + baselineY); | 770 metrics->setFontBoundingBoxDescent(descent + baselineY); |
762 metrics->setActualBoundingBoxAscent(-textBounds.y() - baselineY); | 771 metrics->setActualBoundingBoxAscent(-textBounds.y() - baselineY); |
763 metrics->setActualBoundingBoxDescent(textBounds.maxY() + baselineY); | 772 metrics->setActualBoundingBoxDescent(textBounds.maxY() + baselineY); |
764 | 773 |
765 // Note : top/bottom and ascend/descend are currently the same, so there's no
difference | 774 // Note : top/bottom and ascend/descend are currently the same, so there's no |
766 // between the EM box's top and bottom and the font's ascend and descen
d | 775 // difference between the EM box's top and bottom and the font's ascend and |
| 776 // descend |
767 metrics->setEmHeightAscent(0); | 777 metrics->setEmHeightAscent(0); |
768 metrics->setEmHeightDescent(0); | 778 metrics->setEmHeightDescent(0); |
769 | 779 |
770 metrics->setHangingBaseline(0.8f * ascent - baselineY); | 780 metrics->setHangingBaseline(0.8f * ascent - baselineY); |
771 metrics->setAlphabeticBaseline(-baselineY); | 781 metrics->setAlphabeticBaseline(-baselineY); |
772 metrics->setIdeographicBaseline(-descent - baselineY); | 782 metrics->setIdeographicBaseline(-descent - baselineY); |
773 return metrics; | 783 return metrics; |
774 } | 784 } |
775 | 785 |
776 void CanvasRenderingContext2D::drawTextInternal( | 786 void CanvasRenderingContext2D::drawTextInternal( |
777 const String& text, | 787 const String& text, |
778 double x, | 788 double x, |
779 double y, | 789 double y, |
780 CanvasRenderingContext2DState::PaintType paintType, | 790 CanvasRenderingContext2DState::PaintType paintType, |
781 double* maxWidth) { | 791 double* maxWidth) { |
782 // The style resolution required for fonts is not available in frame-less docu
ments. | 792 // The style resolution required for fonts is not available in frame-less |
| 793 // documents. |
783 if (!canvas()->document().frame()) | 794 if (!canvas()->document().frame()) |
784 return; | 795 return; |
785 | 796 |
786 // accessFont needs the style to be up to date, but updating style can cause s
cript to run, | 797 // accessFont needs the style to be up to date, but updating style can cause |
787 // (e.g. due to autofocus) which can free the canvas (set size to 0, for examp
le), so update | 798 // script to run, (e.g. due to autofocus) which can free the canvas (set size |
788 // style before grabbing the drawingCanvas. | 799 // to 0, for example), so update style before grabbing the drawingCanvas. |
789 canvas()->document().updateStyleAndLayoutTreeForNode(canvas()); | 800 canvas()->document().updateStyleAndLayoutTreeForNode(canvas()); |
790 | 801 |
791 SkCanvas* c = drawingCanvas(); | 802 SkCanvas* c = drawingCanvas(); |
792 if (!c) | 803 if (!c) |
793 return; | 804 return; |
794 | 805 |
795 if (!std::isfinite(x) || !std::isfinite(y)) | 806 if (!std::isfinite(x) || !std::isfinite(y)) |
796 return; | 807 return; |
797 if (maxWidth && (!std::isfinite(*maxWidth) || *maxWidth <= 0)) | 808 if (maxWidth && (!std::isfinite(*maxWidth) || *maxWidth <= 0)) |
798 return; | 809 return; |
799 | 810 |
800 // Currently, SkPictureImageFilter does not support subpixel text anti-aliasin
g, which | 811 // Currently, SkPictureImageFilter does not support subpixel text |
801 // is expected when !creationAttributes().alpha(), so we need to fall out of d
isplay | 812 // anti-aliasing, which is expected when !creationAttributes().alpha(), so we |
802 // list mode when drawing text to an opaque canvas. | 813 // need to fall out of display list mode when drawing text to an opaque |
803 // crbug.com/583809 | 814 // canvas. crbug.com/583809 |
804 if (!creationAttributes().alpha() && !isAccelerated()) | 815 if (!creationAttributes().alpha() && !isAccelerated()) |
805 canvas()->disableDeferral( | 816 canvas()->disableDeferral( |
806 DisableDeferralReasonSubPixelTextAntiAliasingSupport); | 817 DisableDeferralReasonSubPixelTextAntiAliasingSupport); |
807 | 818 |
808 const Font& font = accessFont(); | 819 const Font& font = accessFont(); |
809 if (!font.primaryFont()) | 820 if (!font.primaryFont()) |
810 return; | 821 return; |
811 | 822 |
812 const FontMetrics& fontMetrics = font.getFontMetrics(); | 823 const FontMetrics& fontMetrics = font.getFontMetrics(); |
813 | 824 |
(...skipping 26 matching lines...) Expand all Loading... |
840 case CenterTextAlign: | 851 case CenterTextAlign: |
841 location.setX(location.x() - width / 2); | 852 location.setX(location.x() - width / 2); |
842 break; | 853 break; |
843 case RightTextAlign: | 854 case RightTextAlign: |
844 location.setX(location.x() - width); | 855 location.setX(location.x() - width); |
845 break; | 856 break; |
846 default: | 857 default: |
847 break; | 858 break; |
848 } | 859 } |
849 | 860 |
850 // The slop built in to this mask rect matches the heuristic used in FontCGWin
.cpp for GDI text. | 861 // The slop built in to this mask rect matches the heuristic used in |
| 862 // FontCGWin.cpp for GDI text. |
851 TextRunPaintInfo textRunPaintInfo(textRun); | 863 TextRunPaintInfo textRunPaintInfo(textRun); |
852 textRunPaintInfo.bounds = | 864 textRunPaintInfo.bounds = |
853 FloatRect(location.x() - fontMetrics.height() / 2, | 865 FloatRect(location.x() - fontMetrics.height() / 2, |
854 location.y() - fontMetrics.ascent() - fontMetrics.lineGap(), | 866 location.y() - fontMetrics.ascent() - fontMetrics.lineGap(), |
855 width + fontMetrics.height(), fontMetrics.lineSpacing()); | 867 width + fontMetrics.height(), fontMetrics.lineSpacing()); |
856 if (paintType == CanvasRenderingContext2DState::StrokePaintType) | 868 if (paintType == CanvasRenderingContext2DState::StrokePaintType) |
857 inflateStrokeRect(textRunPaintInfo.bounds); | 869 inflateStrokeRect(textRunPaintInfo.bounds); |
858 | 870 |
859 CanvasRenderingContext2DAutoRestoreSkCanvas stateRestorer(this); | 871 CanvasRenderingContext2DAutoRestoreSkCanvas stateRestorer(this); |
860 if (useMaxWidth) { | 872 if (useMaxWidth) { |
861 drawingCanvas()->save(); | 873 drawingCanvas()->save(); |
862 drawingCanvas()->translate(location.x(), location.y()); | 874 drawingCanvas()->translate(location.x(), location.y()); |
863 // We draw when fontWidth is 0 so compositing operations (eg, a "copy" op) s
till work. | 875 // We draw when fontWidth is 0 so compositing operations (eg, a "copy" op) |
| 876 // still work. |
864 drawingCanvas()->scale((fontWidth > 0 ? (width / fontWidth) : 0), 1); | 877 drawingCanvas()->scale((fontWidth > 0 ? (width / fontWidth) : 0), 1); |
865 location = FloatPoint(); | 878 location = FloatPoint(); |
866 } | 879 } |
867 | 880 |
868 draw( | 881 draw( |
869 [&font, this, &textRunPaintInfo, &location]( | 882 [&font, this, &textRunPaintInfo, &location]( |
870 SkCanvas* c, const SkPaint* paint) // draw lambda | 883 SkCanvas* c, const SkPaint* paint) // draw lambda |
871 { | 884 { |
872 font.drawBidiText(c, textRunPaintInfo, location, | 885 font.drawBidiText(c, textRunPaintInfo, location, |
873 Font::UseFallbackIfFontNotReady, cDeviceScaleFactor, | 886 Font::UseFallbackIfFontNotReady, cDeviceScaleFactor, |
(...skipping 10 matching lines...) Expand all Loading... |
884 canvas()->document().canvasFontCache()->willUseCurrentFont(); | 897 canvas()->document().canvasFontCache()->willUseCurrentFont(); |
885 return state().font(); | 898 return state().font(); |
886 } | 899 } |
887 | 900 |
888 int CanvasRenderingContext2D::getFontBaseline( | 901 int CanvasRenderingContext2D::getFontBaseline( |
889 const FontMetrics& fontMetrics) const { | 902 const FontMetrics& fontMetrics) const { |
890 switch (state().getTextBaseline()) { | 903 switch (state().getTextBaseline()) { |
891 case TopTextBaseline: | 904 case TopTextBaseline: |
892 return fontMetrics.ascent(); | 905 return fontMetrics.ascent(); |
893 case HangingTextBaseline: | 906 case HangingTextBaseline: |
894 // According to http://wiki.apache.org/xmlgraphics-fop/LineLayout/Alignmen
tHandling | 907 // According to |
895 // "FOP (Formatting Objects Processor) puts the hanging baseline at 80% of
the ascender height" | 908 // http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling |
| 909 // "FOP (Formatting Objects Processor) puts the hanging baseline at 80% of |
| 910 // the ascender height" |
896 return (fontMetrics.ascent() * 4) / 5; | 911 return (fontMetrics.ascent() * 4) / 5; |
897 case BottomTextBaseline: | 912 case BottomTextBaseline: |
898 case IdeographicTextBaseline: | 913 case IdeographicTextBaseline: |
899 return -fontMetrics.descent(); | 914 return -fontMetrics.descent(); |
900 case MiddleTextBaseline: | 915 case MiddleTextBaseline: |
901 return -fontMetrics.descent() + fontMetrics.height() / 2; | 916 return -fontMetrics.descent() + fontMetrics.height() / 2; |
902 case AlphabeticTextBaseline: | 917 case AlphabeticTextBaseline: |
903 default: | 918 default: |
904 // Do nothing. | 919 // Do nothing. |
905 break; | 920 break; |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1082 | 1097 |
1083 unsigned CanvasRenderingContext2D::hitRegionsCount() const { | 1098 unsigned CanvasRenderingContext2D::hitRegionsCount() const { |
1084 if (m_hitRegionManager) | 1099 if (m_hitRegionManager) |
1085 return m_hitRegionManager->getHitRegionsCount(); | 1100 return m_hitRegionManager->getHitRegionsCount(); |
1086 | 1101 |
1087 return 0; | 1102 return 0; |
1088 } | 1103 } |
1089 | 1104 |
1090 bool CanvasRenderingContext2D::isAccelerationOptimalForCanvasContent() const { | 1105 bool CanvasRenderingContext2D::isAccelerationOptimalForCanvasContent() const { |
1091 // Heuristic to determine if the GPU accelerated rendering pipeline is optimal | 1106 // Heuristic to determine if the GPU accelerated rendering pipeline is optimal |
1092 // for performance based on past usage. It has a bias towards suggesting that
the | 1107 // for performance based on past usage. It has a bias towards suggesting that |
1093 // accelerated pipeline is optimal. | 1108 // the accelerated pipeline is optimal. |
1094 | 1109 |
1095 float acceleratedCost = estimateRenderingCost( | 1110 float acceleratedCost = estimateRenderingCost( |
1096 ExpensiveCanvasHeuristicParameters::AcceleratedModeIndex); | 1111 ExpensiveCanvasHeuristicParameters::AcceleratedModeIndex); |
1097 | 1112 |
1098 float recordingCost = estimateRenderingCost( | 1113 float recordingCost = estimateRenderingCost( |
1099 ExpensiveCanvasHeuristicParameters::RecordingModeIndex); | 1114 ExpensiveCanvasHeuristicParameters::RecordingModeIndex); |
1100 | 1115 |
1101 float costDifference = acceleratedCost - recordingCost; | 1116 float costDifference = acceleratedCost - recordingCost; |
1102 float percentCostReduction = costDifference / acceleratedCost * 100.0; | 1117 float percentCostReduction = costDifference / acceleratedCost * 100.0; |
1103 float costDifferencePerFrame = | 1118 float costDifferencePerFrame = |
1104 costDifference / m_usageCounters.numFramesSinceReset; | 1119 costDifference / m_usageCounters.numFramesSinceReset; |
1105 | 1120 |
1106 if (percentCostReduction >= | 1121 if (percentCostReduction >= |
1107 ExpensiveCanvasHeuristicParameters:: | 1122 ExpensiveCanvasHeuristicParameters:: |
1108 MinPercentageImprovementToSuggestDisableAcceleration && | 1123 MinPercentageImprovementToSuggestDisableAcceleration && |
1109 costDifferencePerFrame >= | 1124 costDifferencePerFrame >= |
1110 ExpensiveCanvasHeuristicParameters:: | 1125 ExpensiveCanvasHeuristicParameters:: |
1111 MinCostPerFrameImprovementToSuggestDisableAcceleration) { | 1126 MinCostPerFrameImprovementToSuggestDisableAcceleration) { |
1112 return false; | 1127 return false; |
1113 } | 1128 } |
1114 return true; | 1129 return true; |
1115 } | 1130 } |
1116 | 1131 |
1117 void CanvasRenderingContext2D::resetUsageTracking() { | 1132 void CanvasRenderingContext2D::resetUsageTracking() { |
1118 UsageCounters newCounters; | 1133 UsageCounters newCounters; |
1119 m_usageCounters = newCounters; | 1134 m_usageCounters = newCounters; |
1120 } | 1135 } |
1121 | 1136 |
1122 } // namespace blink | 1137 } // namespace blink |
OLD | NEW |