tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Slot.cpp (19139B)


      1 /*  GRAPHITE2 LICENSING
      2 
      3    Copyright 2010, SIL International
      4    All rights reserved.
      5 
      6    This library is free software; you can redistribute it and/or modify
      7    it under the terms of the GNU Lesser General Public License as published
      8    by the Free Software Foundation; either version 2.1 of License, or
      9    (at your option) any later version.
     10 
     11    This program is distributed in the hope that it will be useful,
     12    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14    Lesser General Public License for more details.
     15 
     16    You should also have received a copy of the GNU Lesser General Public
     17    License along with this library in the file named "LICENSE".
     18    If not, write to the Free Software Foundation, 51 Franklin Street,
     19    Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
     20    internet at http://www.fsf.org/licenses/lgpl.html.
     21 
     22 Alternatively, the contents of this file may be used under the terms of the
     23 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
     24 License, as published by the Free Software Foundation, either version 2
     25 of the License or (at your option) any later version.
     26 */
     27 #include "inc/Segment.h"
     28 #include "inc/Slot.h"
     29 #include "inc/Silf.h"
     30 #include "inc/CharInfo.h"
     31 #include "inc/Rule.h"
     32 #include "inc/Collider.h"
     33 
     34 
     35 using namespace graphite2;
     36 
     37 Slot::Slot(int16 *user_attrs) :
     38    m_next(NULL), m_prev(NULL),
     39    m_glyphid(0), m_realglyphid(0), m_original(0), m_before(0), m_after(0),
     40    m_index(0), m_parent(NULL), m_child(NULL), m_sibling(NULL),
     41    m_position(0, 0), m_shift(0, 0), m_advance(0, 0),
     42    m_attach(0, 0), m_with(0, 0), m_just(0.),
     43    m_flags(0), m_attLevel(0), m_bidiCls(-1), m_bidiLevel(0),
     44    m_userAttr(user_attrs), m_justs(NULL)
     45 {
     46 }
     47 
     48 // take care, this does not copy any of the GrSlot pointer fields
     49 void Slot::set(const Slot & orig, int charOffset, size_t sizeAttr, size_t justLevels, size_t numChars)
     50 {
     51    // leave m_next and m_prev unchanged
     52    m_glyphid = orig.m_glyphid;
     53    m_realglyphid = orig.m_realglyphid;
     54    m_original = orig.m_original + charOffset;
     55    if (charOffset + int(orig.m_before) < 0)
     56        m_before = 0;
     57    else
     58        m_before = orig.m_before + charOffset;
     59    if (charOffset <= 0 && orig.m_after + charOffset >= numChars)
     60        m_after = int(numChars) - 1;
     61    else
     62        m_after = orig.m_after + charOffset;
     63    m_parent = NULL;
     64    m_child = NULL;
     65    m_sibling = NULL;
     66    m_position = orig.m_position;
     67    m_shift = orig.m_shift;
     68    m_advance = orig.m_advance;
     69    m_attach = orig.m_attach;
     70    m_with = orig.m_with;
     71    m_flags = orig.m_flags;
     72    m_attLevel = orig.m_attLevel;
     73    m_bidiCls = orig.m_bidiCls;
     74    m_bidiLevel = orig.m_bidiLevel;
     75    if (m_userAttr && orig.m_userAttr)
     76        memcpy(m_userAttr, orig.m_userAttr, sizeAttr * sizeof(*m_userAttr));
     77    if (m_justs && orig.m_justs)
     78        memcpy(m_justs, orig.m_justs, SlotJustify::size_of(justLevels));
     79 }
     80 
     81 void Slot::update(int /*numGrSlots*/, int numCharInfo, Position &relpos)
     82 {
     83    m_before += numCharInfo;
     84    m_after += numCharInfo;
     85    m_position = m_position + relpos;
     86 }
     87 
     88 Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal, int depth)
     89 {
     90    SlotCollision *coll = NULL;
     91    if (depth > 100 || (attrLevel && m_attLevel > attrLevel)) return Position(0, 0);
     92    float scale = font ? font->scale() : 1.0f;
     93    Position shift(m_shift.x * (rtl * -2 + 1) + m_just, m_shift.y);
     94    float tAdvance = m_advance.x + m_just;
     95    if (isFinal && (coll = seg->collisionInfo(this)))
     96    {
     97        const Position &collshift = coll->offset();
     98        if (!(coll->flags() & SlotCollision::COLL_KERN) || rtl)
     99            shift = shift + collshift;
    100    }
    101    const GlyphFace * glyphFace = seg->getFace()->glyphs().glyphSafe(glyph());
    102    if (font)
    103    {
    104        scale = font->scale();
    105        shift *= scale;
    106        if (font->isHinted() && glyphFace)
    107            tAdvance = (m_advance.x - glyphFace->theAdvance().x + m_just) * scale + font->advance(glyph());
    108        else
    109            tAdvance *= scale;
    110    }
    111    Position res;
    112 
    113    m_position = base + shift;
    114    if (!m_parent)
    115    {
    116        res = base + Position(tAdvance, m_advance.y * scale);
    117        clusterMin = m_position.x;
    118    }
    119    else
    120    {
    121        float tAdv;
    122        m_position += (m_attach - m_with) * scale;
    123        tAdv = m_advance.x >= 0.5f ? m_position.x + tAdvance - shift.x : 0.f;
    124        res = Position(tAdv, 0);
    125        if ((m_advance.x >= 0.5f || m_position.x < 0) && m_position.x < clusterMin) clusterMin = m_position.x;
    126    }
    127 
    128    if (glyphFace)
    129    {
    130        Rect ourBbox = glyphFace->theBBox() * scale + m_position;
    131        bbox = bbox.widen(ourBbox);
    132    }
    133 
    134    if (m_child && m_child != this && m_child->attachedTo() == this)
    135    {
    136        Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin, rtl, isFinal, depth + 1);
    137        if ((!m_parent || m_advance.x >= 0.5f) && tRes.x > res.x) res = tRes;
    138    }
    139 
    140    if (m_parent && m_sibling && m_sibling != this && m_sibling->attachedTo() == m_parent)
    141    {
    142        Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin, rtl, isFinal, depth + 1);
    143        if (tRes.x > res.x) res = tRes;
    144    }
    145 
    146    if (!m_parent && clusterMin < base.x)
    147    {
    148        Position adj = Position(m_position.x - clusterMin, 0.);
    149        res += adj;
    150        m_position += adj;
    151        if (m_child) m_child->floodShift(adj);
    152    }
    153    return res;
    154 }
    155 
    156 int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel, bool rtl)
    157 {
    158    Position base;
    159    if (glyph() >= seg->getFace()->glyphs().numGlyphs())
    160        return 0;
    161    Rect bbox = seg->theGlyphBBoxTemporary(glyph());
    162    float clusterMin = 0.;
    163    Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin, rtl, false);
    164 
    165    switch (metrics(metric))
    166    {
    167    case kgmetLsb :
    168        return int32(bbox.bl.x);
    169    case kgmetRsb :
    170        return int32(res.x - bbox.tr.x);
    171    case kgmetBbTop :
    172        return int32(bbox.tr.y);
    173    case kgmetBbBottom :
    174        return int32(bbox.bl.y);
    175    case kgmetBbLeft :
    176        return int32(bbox.bl.x);
    177    case kgmetBbRight :
    178        return int32(bbox.tr.x);
    179    case kgmetBbWidth :
    180        return int32(bbox.tr.x - bbox.bl.x);
    181    case kgmetBbHeight :
    182        return int32(bbox.tr.y - bbox.bl.y);
    183    case kgmetAdvWidth :
    184        return int32(res.x);
    185    case kgmetAdvHeight :
    186        return int32(res.y);
    187    default :
    188        return 0;
    189    }
    190 }
    191 
    192 #define SLOTGETCOLATTR(x) { SlotCollision *c = seg->collisionInfo(this); return c ? int(c-> x) : 0; }
    193 
    194 int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
    195 {
    196    if (ind >= gr_slatJStretch && ind < gr_slatJStretch + 20 && ind != gr_slatJWidth)
    197    {
    198        int indx = ind - gr_slatJStretch;
    199        return getJustify(seg, indx / 5, indx % 5);
    200    }
    201 
    202    switch (ind)
    203    {
    204    case gr_slatAdvX :      return int(m_advance.x);
    205    case gr_slatAdvY :      return int(m_advance.y);
    206    case gr_slatAttTo :     return m_parent ? 1 : 0;
    207    case gr_slatAttX :      return int(m_attach.x);
    208    case gr_slatAttY :      return int(m_attach.y);
    209    case gr_slatAttXOff :
    210    case gr_slatAttYOff :   return 0;
    211    case gr_slatAttWithX :  return int(m_with.x);
    212    case gr_slatAttWithY :  return int(m_with.y);
    213    case gr_slatAttWithXOff:
    214    case gr_slatAttWithYOff:return 0;
    215    case gr_slatAttLevel :  return m_attLevel;
    216    case gr_slatBreak :     return seg->charinfo(m_original)->breakWeight();
    217    case gr_slatCompRef :   return 0;
    218    case gr_slatDir :       return seg->dir() & 1;
    219    case gr_slatInsert :    return isInsertBefore();
    220    case gr_slatPosX :      return int(m_position.x); // but need to calculate it
    221    case gr_slatPosY :      return int(m_position.y);
    222    case gr_slatShiftX :    return int(m_shift.x);
    223    case gr_slatShiftY :    return int(m_shift.y);
    224    case gr_slatMeasureSol: return -1; // err what's this?
    225    case gr_slatMeasureEol: return -1;
    226    case gr_slatJWidth:     return int(m_just);
    227    case gr_slatUserDefnV1: subindex = 0; GR_FALLTHROUGH;
    228      // no break
    229    case gr_slatUserDefn :  return subindex < seg->numAttrs() ?  m_userAttr[subindex] : 0;
    230    case gr_slatSegSplit :  return seg->charinfo(m_original)->flags() & 3;
    231    case gr_slatBidiLevel:  return m_bidiLevel;
    232    case gr_slatColFlags :		{ SlotCollision *c = seg->collisionInfo(this); return c ? c->flags() : 0; }
    233    case gr_slatColLimitblx:SLOTGETCOLATTR(limit().bl.x)
    234    case gr_slatColLimitbly:SLOTGETCOLATTR(limit().bl.y)
    235    case gr_slatColLimittrx:SLOTGETCOLATTR(limit().tr.x)
    236    case gr_slatColLimittry:SLOTGETCOLATTR(limit().tr.y)
    237    case gr_slatColShiftx :	SLOTGETCOLATTR(offset().x)
    238    case gr_slatColShifty :	SLOTGETCOLATTR(offset().y)
    239    case gr_slatColMargin :	SLOTGETCOLATTR(margin())
    240    case gr_slatColMarginWt:SLOTGETCOLATTR(marginWt())
    241    case gr_slatColExclGlyph:SLOTGETCOLATTR(exclGlyph())
    242    case gr_slatColExclOffx:SLOTGETCOLATTR(exclOffset().x)
    243    case gr_slatColExclOffy:SLOTGETCOLATTR(exclOffset().y)
    244    case gr_slatSeqClass :	SLOTGETCOLATTR(seqClass())
    245    case gr_slatSeqProxClass:SLOTGETCOLATTR(seqProxClass())
    246    case gr_slatSeqOrder :	SLOTGETCOLATTR(seqOrder())
    247    case gr_slatSeqAboveXoff:SLOTGETCOLATTR(seqAboveXoff())
    248    case gr_slatSeqAboveWt: SLOTGETCOLATTR(seqAboveWt())
    249    case gr_slatSeqBelowXlim:SLOTGETCOLATTR(seqBelowXlim())
    250    case gr_slatSeqBelowWt:	SLOTGETCOLATTR(seqBelowWt())
    251    case gr_slatSeqValignHt:SLOTGETCOLATTR(seqValignHt())
    252    case gr_slatSeqValignWt:SLOTGETCOLATTR(seqValignWt())
    253    default : return 0;
    254    }
    255 }
    256 
    257 #define SLOTCOLSETATTR(x) { \
    258        SlotCollision *c = seg->collisionInfo(this); \
    259        if (c) { c-> x ; c->setFlags(c->flags() & ~SlotCollision::COLL_KNOWN); } \
    260        break; }
    261 #define SLOTCOLSETCOMPLEXATTR(t, y, x) { \
    262        SlotCollision *c = seg->collisionInfo(this); \
    263        if (c) { \
    264        const t &s = c-> y; \
    265        c-> x ; c->setFlags(c->flags() & ~SlotCollision::COLL_KNOWN); } \
    266        break; }
    267 
    268 void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, const SlotMap & map)
    269 {
    270    if (ind == gr_slatUserDefnV1)
    271    {
    272        ind = gr_slatUserDefn;
    273        subindex = 0;
    274        if (seg->numAttrs() == 0)
    275            return;
    276    }
    277    else if (ind >= gr_slatJStretch && ind < gr_slatJStretch + 20 && ind != gr_slatJWidth)
    278    {
    279        int indx = ind - gr_slatJStretch;
    280        return setJustify(seg, indx / 5, indx % 5, value);
    281    }
    282 
    283    switch (ind)
    284    {
    285    case gr_slatAdvX :  m_advance.x = value; break;
    286    case gr_slatAdvY :  m_advance.y = value; break;
    287    case gr_slatAttTo :
    288    {
    289        const uint16 idx = uint16(value);
    290        if (idx < map.size() && map[idx])
    291        {
    292            Slot *other = map[idx];
    293            if (other == this || other == m_parent || other->isCopied()) break;
    294            if (m_parent) { m_parent->removeChild(this); attachTo(NULL); }
    295            Slot *pOther = other;
    296            int count = 0;
    297            bool foundOther = false;
    298            while (pOther)
    299            {
    300                ++count;
    301                if (pOther == this) foundOther = true;
    302                pOther = pOther->attachedTo();
    303            }
    304            for (pOther = m_child; pOther; pOther = pOther->m_child)
    305                ++count;
    306            for (pOther = m_sibling; pOther; pOther = pOther->m_sibling)
    307                ++count;
    308            if (count < 100 && !foundOther && other->child(this))
    309            {
    310                attachTo(other);
    311                if ((map.dir() != 0) ^ (idx > subindex))
    312                    m_with = Position(advance(), 0);
    313                else        // normal match to previous root
    314                    m_attach = Position(other->advance(), 0);
    315            }
    316        }
    317        break;
    318    }
    319    case gr_slatAttX :          m_attach.x = value; break;
    320    case gr_slatAttY :          m_attach.y = value; break;
    321    case gr_slatAttXOff :
    322    case gr_slatAttYOff :       break;
    323    case gr_slatAttWithX :      m_with.x = value; break;
    324    case gr_slatAttWithY :      m_with.y = value; break;
    325    case gr_slatAttWithXOff :
    326    case gr_slatAttWithYOff :   break;
    327    case gr_slatAttLevel :
    328        m_attLevel = byte(value);
    329        break;
    330    case gr_slatBreak :
    331        seg->charinfo(m_original)->breakWeight(value);
    332        break;
    333    case gr_slatCompRef :   break;      // not sure what to do here
    334    case gr_slatDir : break;
    335    case gr_slatInsert :
    336        markInsertBefore(value? true : false);
    337        break;
    338    case gr_slatPosX :      break; // can't set these here
    339    case gr_slatPosY :      break;
    340    case gr_slatShiftX :    m_shift.x = value; break;
    341    case gr_slatShiftY :    m_shift.y = value; break;
    342    case gr_slatMeasureSol :    break;
    343    case gr_slatMeasureEol :    break;
    344    case gr_slatJWidth :    just(value); break;
    345    case gr_slatSegSplit :  seg->charinfo(m_original)->addflags(value & 3); break;
    346    case gr_slatUserDefn :  m_userAttr[subindex] = value; break;
    347    case gr_slatColFlags :  {
    348        SlotCollision *c = seg->collisionInfo(this);
    349        if (c)
    350            c->setFlags(value);
    351        break; }
    352    case gr_slatColLimitblx :	SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(Position(value, s.bl.y), s.tr)))
    353    case gr_slatColLimitbly :	SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(Position(s.bl.x, value), s.tr)))
    354    case gr_slatColLimittrx :	SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(s.bl, Position(value, s.tr.y))))
    355    case gr_slatColLimittry :	SLOTCOLSETCOMPLEXATTR(Rect, limit(), setLimit(Rect(s.bl, Position(s.tr.x, value))))
    356    case gr_slatColMargin :		SLOTCOLSETATTR(setMargin(value))
    357    case gr_slatColMarginWt :	SLOTCOLSETATTR(setMarginWt(value))
    358    case gr_slatColExclGlyph :	SLOTCOLSETATTR(setExclGlyph(value))
    359    case gr_slatColExclOffx :	SLOTCOLSETCOMPLEXATTR(Position, exclOffset(), setExclOffset(Position(value, s.y)))
    360    case gr_slatColExclOffy :	SLOTCOLSETCOMPLEXATTR(Position, exclOffset(), setExclOffset(Position(s.x, value)))
    361    case gr_slatSeqClass :		SLOTCOLSETATTR(setSeqClass(value))
    362 case gr_slatSeqProxClass :	SLOTCOLSETATTR(setSeqProxClass(value))
    363    case gr_slatSeqOrder :		SLOTCOLSETATTR(setSeqOrder(value))
    364    case gr_slatSeqAboveXoff :	SLOTCOLSETATTR(setSeqAboveXoff(value))
    365    case gr_slatSeqAboveWt :	SLOTCOLSETATTR(setSeqAboveWt(value))
    366    case gr_slatSeqBelowXlim :	SLOTCOLSETATTR(setSeqBelowXlim(value))
    367    case gr_slatSeqBelowWt :	SLOTCOLSETATTR(setSeqBelowWt(value))
    368    case gr_slatSeqValignHt :	SLOTCOLSETATTR(setSeqValignHt(value))
    369    case gr_slatSeqValignWt :	SLOTCOLSETATTR(setSeqValignWt(value))
    370    default :
    371        break;
    372    }
    373 }
    374 
    375 int Slot::getJustify(const Segment *seg, uint8 level, uint8 subindex) const
    376 {
    377    if (level && level >= seg->silf()->numJustLevels()) return 0;
    378 
    379    if (m_justs)
    380        return m_justs->values[level * SlotJustify::NUMJUSTPARAMS + subindex];
    381 
    382    if (level >= seg->silf()->numJustLevels()) return 0;
    383    Justinfo *jAttrs = seg->silf()->justAttrs() + level;
    384 
    385    switch (subindex) {
    386        case 0 : return seg->glyphAttr(gid(), jAttrs->attrStretch());
    387        case 1 : return seg->glyphAttr(gid(), jAttrs->attrShrink());
    388        case 2 : return seg->glyphAttr(gid(), jAttrs->attrStep());
    389        case 3 : return seg->glyphAttr(gid(), jAttrs->attrWeight());
    390        case 4 : return 0;      // not been set yet, so clearly 0
    391        default: return 0;
    392    }
    393 }
    394 
    395 void Slot::setJustify(Segment *seg, uint8 level, uint8 subindex, int16 value)
    396 {
    397    if (level && level >= seg->silf()->numJustLevels()) return;
    398    if (!m_justs)
    399    {
    400        SlotJustify *j = seg->newJustify();
    401        if (!j) return;
    402        j->LoadSlot(this, seg);
    403        m_justs = j;
    404    }
    405    m_justs->values[level * SlotJustify::NUMJUSTPARAMS + subindex] = value;
    406 }
    407 
    408 bool Slot::child(Slot *ap)
    409 {
    410    if (this == ap) return false;
    411    else if (ap == m_child) return true;
    412    else if (!m_child)
    413        m_child = ap;
    414    else
    415        return m_child->sibling(ap);
    416    return true;
    417 }
    418 
    419 bool Slot::sibling(Slot *ap)
    420 {
    421    if (this == ap) return false;
    422    else if (ap == m_sibling) return true;
    423    else if (!m_sibling || !ap)
    424        m_sibling = ap;
    425    else
    426        return m_sibling->sibling(ap);
    427    return true;
    428 }
    429 
    430 bool Slot::removeChild(Slot *ap)
    431 {
    432    if (this == ap || !m_child || !ap) return false;
    433    else if (ap == m_child)
    434    {
    435        Slot *nSibling = m_child->nextSibling();
    436        m_child->nextSibling(NULL);
    437        m_child = nSibling;
    438        return true;
    439    }
    440    for (Slot *p = m_child; p; p = p->m_sibling)
    441    {
    442        if (p->m_sibling && p->m_sibling == ap)
    443        {
    444            p->m_sibling = p->m_sibling->m_sibling;
    445            ap->nextSibling(NULL);
    446            return true;
    447        }
    448    }
    449    return false;
    450 }
    451 
    452 void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph)
    453 {
    454    m_glyphid = glyphid;
    455    m_bidiCls = -1;
    456    if (!theGlyph)
    457    {
    458        theGlyph = seg->getFace()->glyphs().glyphSafe(glyphid);
    459        if (!theGlyph)
    460        {
    461            m_realglyphid = 0;
    462            m_advance = Position(0.,0.);
    463            return;
    464        }
    465    }
    466    m_realglyphid = theGlyph->attrs()[seg->silf()->aPseudo()];
    467    if (m_realglyphid > seg->getFace()->glyphs().numGlyphs())
    468        m_realglyphid = 0;
    469    const GlyphFace *aGlyph = theGlyph;
    470    if (m_realglyphid)
    471    {
    472        aGlyph = seg->getFace()->glyphs().glyphSafe(m_realglyphid);
    473        if (!aGlyph) aGlyph = theGlyph;
    474    }
    475    m_advance = Position(aGlyph->theAdvance().x, 0.);
    476    if (seg->silf()->aPassBits())
    477    {
    478        seg->mergePassBits(uint8(theGlyph->attrs()[seg->silf()->aPassBits()]));
    479        if (seg->silf()->numPasses() > 16)
    480            seg->mergePassBits(theGlyph->attrs()[seg->silf()->aPassBits()+1] << 16);
    481    }
    482 }
    483 
    484 void Slot::floodShift(Position adj, int depth)
    485 {
    486    if (depth > 100)
    487        return;
    488    m_position += adj;
    489    if (m_child) m_child->floodShift(adj, depth + 1);
    490    if (m_sibling) m_sibling->floodShift(adj, depth + 1);
    491 }
    492 
    493 void SlotJustify::LoadSlot(const Slot *s, const Segment *seg)
    494 {
    495    for (int i = seg->silf()->numJustLevels() - 1; i >= 0; --i)
    496    {
    497        Justinfo *justs = seg->silf()->justAttrs() + i;
    498        int16 *v = values + i * NUMJUSTPARAMS;
    499        v[0] = seg->glyphAttr(s->gid(), justs->attrStretch());
    500        v[1] = seg->glyphAttr(s->gid(), justs->attrShrink());
    501        v[2] = seg->glyphAttr(s->gid(), justs->attrStep());
    502        v[3] = seg->glyphAttr(s->gid(), justs->attrWeight());
    503    }
    504 }
    505 
    506 Slot * Slot::nextInCluster(const Slot *s) const
    507 {
    508    Slot *base;
    509    if (s->firstChild())
    510        return s->firstChild();
    511    else if (s->nextSibling())
    512        return s->nextSibling();
    513    while ((base = s->attachedTo()))
    514    {
    515        // if (base->firstChild() == s && base->nextSibling())
    516        if (base->nextSibling())
    517            return base->nextSibling();
    518        s = base;
    519    }
    520    return NULL;
    521 }
    522 
    523 bool Slot::isChildOf(const Slot *base) const
    524 {
    525    for (Slot *p = m_parent; p; p = p->m_parent)
    526        if (p == base)
    527            return true;
    528    return false;
    529 }