1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "config.h" 6 #include "core/html/canvas/HitRegion.h" 7 8 #include "core/accessibility/AXObjectCache.h" 9 #include "core/rendering/RenderBoxModelObject.h" 10 11 namespace blink { 12 13 HitRegion::HitRegion(const HitRegionOptionsInternal& options) 14 : m_id(options.id) 15 , m_control(options.control) 16 , m_path(options.path) 17 , m_fillRule(options.fillRule) 18 { 19 } 20 21 void HitRegion::updateAccessibility(Element* canvas) 22 { 23 if (!m_control || !canvas || !canvas->renderer() || !m_control->isDescendantOf(canvas)) 24 return; 25 26 AXObjectCache* axObjectCache = m_control->document().existingAXObjectCache(); 27 if (!axObjectCache) 28 return; 29 30 FloatRect boundingRect = m_path.boundingRect(); 31 32 // Offset by the canvas rect, taking border and padding into account. 33 RenderBoxModelObject* rbmo = canvas->renderBoxModelObject(); 34 IntRect canvasRect = canvas->renderer()->absoluteBoundingBoxRect(); 35 canvasRect.move(rbmo->borderLeft() + rbmo->paddingLeft(), 36 rbmo->borderTop() + rbmo->paddingTop()); 37 LayoutRect elementRect = enclosingLayoutRect(boundingRect); 38 elementRect.moveBy(canvasRect.location()); 39 40 axObjectCache->setCanvasObjectBounds(m_control.get(), elementRect); 41 } 42 43 bool HitRegion::contains(const LayoutPoint& point) const 44 { 45 return m_path.contains(point, m_fillRule); 46 } 47 48 void HitRegion::removePixels(const Path& clearArea) 49 { 50 m_path.subtractPath(clearArea); 51 } 52 53 void HitRegion::trace(Visitor* visitor) 54 { 55 visitor->trace(m_control); 56 } 57 58 void HitRegionManager::addHitRegion(PassRefPtrWillBeRawPtr<HitRegion> passHitRegion) 59 { 60 RefPtrWillBeRawPtr<HitRegion> hitRegion = passHitRegion; 61 62 m_hitRegionList.add(hitRegion); 63 64 if (!hitRegion->id().isEmpty()) 65 m_hitRegionIdMap.set(hitRegion->id(), hitRegion); 66 67 if (hitRegion->control()) 68 m_hitRegionControlMap.set(hitRegion->control(), hitRegion); 69 } 70 71 void HitRegionManager::removeHitRegion(HitRegion* hitRegion) 72 { 73 if (!hitRegion) 74 return; 75 76 if (!hitRegion->id().isEmpty()) 77 m_hitRegionIdMap.remove(hitRegion->id()); 78 79 if (hitRegion->control()) 80 m_hitRegionControlMap.remove(hitRegion->control()); 81 82 m_hitRegionList.remove(hitRegion); 83 } 84 85 void HitRegionManager::removeHitRegionById(const String& id) 86 { 87 if (!id.isEmpty()) 88 removeHitRegion(getHitRegionById(id)); 89 } 90 91 void HitRegionManager::removeHitRegionByControl(Element* control) 92 { 93 removeHitRegion(getHitRegionByControl(control)); 94 } 95 96 void HitRegionManager::removeHitRegionsInRect(const FloatRect& rect, const AffineTransform& ctm) 97 { 98 Path clearArea; 99 clearArea.addRect(rect); 100 clearArea.transform(ctm); 101 102 HitRegionIterator itEnd = m_hitRegionList.rend(); 103 HitRegionList toBeRemoved; 104 105 for (HitRegionIterator it = m_hitRegionList.rbegin(); it != itEnd; ++it) { 106 RefPtrWillBeRawPtr<HitRegion> hitRegion = *it; 107 hitRegion->removePixels(clearArea); 108 if (hitRegion->path().isEmpty()) 109 toBeRemoved.add(hitRegion); 110 } 111 112 itEnd = toBeRemoved.rend(); 113 for (HitRegionIterator it = toBeRemoved.rbegin(); it != itEnd; ++it) 114 removeHitRegion(it->get()); 115 } 116 117 void HitRegionManager::removeAllHitRegions() 118 { 119 m_hitRegionList.clear(); 120 m_hitRegionIdMap.clear(); 121 m_hitRegionControlMap.clear(); 122 } 123 124 HitRegion* HitRegionManager::getHitRegionById(const String& id) const 125 { 126 return m_hitRegionIdMap.get(id); 127 } 128 129 HitRegion* HitRegionManager::getHitRegionByControl(Element* control) const 130 { 131 if (control) 132 return m_hitRegionControlMap.get(control); 133 134 return 0; 135 } 136 137 HitRegion* HitRegionManager::getHitRegionAtPoint(const LayoutPoint& point) const 138 { 139 HitRegionIterator itEnd = m_hitRegionList.rend(); 140 141 for (HitRegionIterator it = m_hitRegionList.rbegin(); it != itEnd; ++it) { 142 RefPtrWillBeRawPtr<HitRegion> hitRegion = *it; 143 if (hitRegion->contains(point)) 144 return hitRegion.get(); 145 } 146 147 return 0; 148 } 149 150 unsigned HitRegionManager::getHitRegionsCount() const 151 { 152 return m_hitRegionList.size(); 153 } 154 155 void HitRegionManager::trace(Visitor* visitor) 156 { 157 #if ENABLE(OILPAN) 158 visitor->trace(m_hitRegionList); 159 visitor->trace(m_hitRegionIdMap); 160 visitor->trace(m_hitRegionControlMap); 161 #endif 162 } 163 164 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(HitRegionManager) 165 166 } // namespace blink 167