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