File indexing completed on 2024-05-05 16:10:28

0001 /*
0002  * This file is part of the DOM implementation for KDE.
0003  *
0004  * Copyright (C) 2008,2009 Maksim Orlovich (maksim@kde.org)
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  *
0021  */
0022 #ifndef _DOM_IDSTRING_h_
0023 #define _DOM_IDSTRING_h_
0024 
0025 #include "misc/shared.h"
0026 #include "dom/dom_string.h"
0027 #include "xml/dom_stringimpl.h"
0028 #include "wtf/Vector.h"
0029 #include <QHash>
0030 
0031 using DOM::DOMString;
0032 using DOM::DOMStringImpl;
0033 
0034 namespace khtml
0035 {
0036 
0037 // When we're working with a case-insensitive language, IDString can lookup
0038 // IDs from strings ignoring the case itself; however it needs to be told
0039 // what the canonical case is, so it knows what hash code to look for.
0040 enum CaseNormalizeMode {
0041     IDS_CaseSensitive,
0042     IDS_NormalizeUpper,
0043     IDS_NormalizeLower
0044 };
0045 
0046 /**
0047  An IDString is used to manage an identifier namespace that has some predefined constants,
0048  but can be extended with new ones at runtime
0049 
0050  The TableFactory template parameter must point to a class
0051  that provides an idTable method returning a singleton IDTable<TableFactory>
0052 */
0053 template<typename TableFactory>
0054 class IDString
0055 {
0056 private:
0057     unsigned short m_id;
0058 
0059 public:
0060     // id 0xFFFF is handled specially in derefId so it's our default..
0061     IDString(): m_id(0xFFFF) {}
0062 
0063     IDString<TableFactory> &operator=(const IDString &other)
0064     {
0065         TableFactory::idTable()->refId(other.m_id);
0066         TableFactory::idTable()->derefId(m_id);
0067         m_id = other.m_id;
0068         return *this;
0069     }
0070 
0071     IDString(const IDString &other)
0072     {
0073         m_id = other.m_id;
0074         TableFactory::idTable()->refId(m_id);
0075     }
0076 
0077     ~IDString()
0078     {
0079         TableFactory::idTable()->derefId(m_id);
0080     }
0081 
0082     unsigned id() const
0083     {
0084         return m_id;
0085     }
0086 
0087     DOMString toString() const
0088     {
0089         return TableFactory::idTable()->idToString(m_id);
0090     }
0091 
0092     static IDString<TableFactory> fromId(unsigned short id)
0093     {
0094         IDString<TableFactory> nw;
0095         nw.m_id = id;
0096         TableFactory::idTable()->refId(id);
0097         return nw;
0098     }
0099 
0100     static IDString<TableFactory> fromString(const DOMString &string, CaseNormalizeMode cnm = IDS_CaseSensitive)
0101     {
0102         return fromString(string.implementation(), cnm);
0103     }
0104 
0105     static IDString<TableFactory> fromString(DOMStringImpl *string, CaseNormalizeMode cnm = IDS_CaseSensitive)
0106     {
0107         IDString<TableFactory> nw;
0108         nw.m_id = TableFactory::idTable()->grabId(string, cnm); // Refs it already.
0109         return nw;
0110     }
0111 
0112     bool operator==(const IDString<TableFactory> &other) const
0113     {
0114         return m_id == other.m_id;
0115     }
0116 
0117     QDebug operator<<(QDebug stream) const
0118     {
0119         return id() ? (stream << id() << toString()) : "null idstring";
0120     }
0121 };
0122 
0123 class IDTableBase
0124 {
0125     struct Mapping {
0126         unsigned        refCount; // # of references, 0 if not in use.
0127         DOMStringImpl  *name;     // same as our key, so no separate
0128         // refcount (except for hidden mappings)
0129 
0130         Mapping(): refCount(0)
0131         {}
0132 
0133         Mapping(DOMStringImpl *_name): refCount(0), name(_name)
0134         {}
0135     };
0136 
0137 public:
0138     // Wraps around DOMString and lets us trigger key sensitivity for lookup;
0139     // that's done via a global fiddle --- warning, warning, warning.
0140     struct MappingKey {
0141         DOMStringImpl *str;
0142         bool operator==(const MappingKey &other) const;
0143 
0144         MappingKey() {}
0145         MappingKey(DOMStringImpl *v): str(v) {}
0146 
0147         static CaseNormalizeMode caseNormalizationMode;
0148     };
0149 protected:
0150     void refId(unsigned id)
0151     {
0152         if (id == 0xFFFF) {
0153             return;
0154         }
0155         ++m_mappings[id].refCount;
0156     }
0157 
0158     void derefId(unsigned id)
0159     {
0160         if (id == 0xFFFF) {
0161             return;
0162         }
0163         --m_mappings[id].refCount;
0164         if (m_mappings[id].refCount == 0) {
0165             releaseId(id);
0166         }
0167     }
0168 
0169     const DOMString idToString(unsigned id)
0170     {
0171         return DOMString(m_mappings[id].name);
0172     }
0173 
0174     unsigned short grabId(DOMStringImpl *string, CaseNormalizeMode cnm);
0175 
0176 public:
0177     // Registers a compile-type known ID constant with the name.
0178     // This must be called before any other operations
0179     void addStaticMapping(unsigned id, const DOMString &string);
0180 
0181     // Registers a hidden ID constant --- it has a name, but it
0182     // can not be looked up by it.
0183     void addHiddenMapping(unsigned id, const DOMString &string);
0184 private:
0185     void releaseId(unsigned id);
0186 
0187     WTF::Vector <unsigned> m_idFreeList;
0188     WTF::Vector <Mapping>  m_mappings;
0189     QHash       <MappingKey, unsigned short> m_mappingLookup;
0190 };
0191 
0192 template<typename TableFactory>
0193 class IDTable: public IDTableBase
0194 {
0195 public:
0196     // Export methods to our version of IDString
0197     friend class IDString<TableFactory>;
0198     using IDTableBase::refId;
0199     using IDTableBase::derefId;
0200     IDTable() {}
0201 };
0202 
0203 }
0204 
0205 /**
0206  Now these are the various ID types we used.. They are here to avoid circular
0207  dependenies in headers
0208 */
0209 namespace DOM
0210 {
0211 class EventImpl;
0212 typedef khtml::IDString<EventImpl> EventName;
0213 }
0214 
0215 #endif