Home | History | Annotate | Download | only in canvas
      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