File indexing completed on 2024-04-28 11:38:44
0001 /** 0002 * This file is part of the HTML rendering engine for KDE. 0003 * 0004 * Copyright (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) 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 0023 #include "rendering/render_generated.h" 0024 #include "rendering/render_style.h" 0025 #include "rendering/enumerate.h" 0026 #include "rendering/counter_tree.h" 0027 #include "css/css_valueimpl.h" 0028 0029 using namespace khtml; 0030 using namespace Enumerate; 0031 0032 // ------------------------------------------------------------------------- 0033 0034 RenderCounterBase::RenderCounterBase(DOM::NodeImpl *node) 0035 : RenderText(node, nullptr), m_counterNode(nullptr) 0036 { 0037 } 0038 0039 void RenderCounterBase::layout() 0040 { 0041 KHTMLAssert(needsLayout()); 0042 0043 if (!minMaxKnown()) { 0044 calcMinMaxWidth(); 0045 } 0046 0047 RenderText::layout(); 0048 } 0049 0050 void RenderCounterBase::calcMinMaxWidth() 0051 { 0052 KHTMLAssert(!minMaxKnown()); 0053 0054 generateContent(); 0055 0056 if (str) { 0057 str->deref(); 0058 } 0059 str = new DOM::DOMStringImpl(m_item.unicode(), m_item.length()); 0060 str->ref(); 0061 0062 RenderText::calcMinMaxWidth(); 0063 } 0064 0065 void RenderCounterBase::updateContent() 0066 { 0067 setMinMaxKnown(false); 0068 } 0069 0070 // ------------------------------------------------------------------------- 0071 0072 RenderCounter::RenderCounter(DOM::NodeImpl *node, const DOM::CounterImpl *counter) 0073 : RenderCounterBase(node), m_counter(counter) 0074 { 0075 } 0076 0077 QString RenderCounter::toListStyleType(int value, int total, EListStyleType type) 0078 { 0079 QString item; 0080 switch (type) { 0081 case LNONE: 0082 break; 0083 // Glyphs: (these values are not really used and instead handled by RenderGlyph) 0084 case LDISC: 0085 item = QChar(0x2022); 0086 break; 0087 case LCIRCLE: 0088 item = QChar(0x25e6); 0089 break; 0090 case LSQUARE: 0091 item = QChar(0x25a0); 0092 break; 0093 case LBOX: 0094 item = QChar(0x25a1); 0095 break; 0096 case LDIAMOND: 0097 item = QChar(0x25c6); 0098 break; 0099 // Numeric: 0100 case LDECIMAL: 0101 item.setNum(value); 0102 break; 0103 case DECIMAL_LEADING_ZERO: { 0104 int decimals = 2; 0105 int t = total / 100; 0106 while (t > 0) { 0107 t = t / 10; 0108 decimals++; 0109 } 0110 decimals = qMax(decimals, 2); 0111 QString num = QString::number(value); 0112 item.fill('0', decimals - num.length()); 0113 item.append(num); 0114 break; 0115 } 0116 case ARABIC_INDIC: 0117 item = toArabicIndic(value); 0118 break; 0119 case LAO: 0120 item = toLao(value); 0121 break; 0122 case PERSIAN: 0123 case URDU: 0124 item = toPersianUrdu(value); 0125 break; 0126 case THAI: 0127 item = toThai(value); 0128 break; 0129 case TIBETAN: 0130 item = toTibetan(value); 0131 break; 0132 // Algoritmic: 0133 case LOWER_ROMAN: 0134 item = toRoman(value, false); 0135 break; 0136 case UPPER_ROMAN: 0137 item = toRoman(value, true); 0138 break; 0139 case HEBREW: 0140 item = toHebrew(value); 0141 break; 0142 case ARMENIAN: 0143 item = toArmenian(value); 0144 break; 0145 case GEORGIAN: 0146 item = toGeorgian(value); 0147 break; 0148 // Alphabetic: 0149 case LOWER_ALPHA: 0150 case LOWER_LATIN: 0151 item = toLowerLatin(value); 0152 break; 0153 case UPPER_ALPHA: 0154 case UPPER_LATIN: 0155 item = toUpperLatin(value); 0156 break; 0157 case LOWER_GREEK: 0158 item = toLowerGreek(value); 0159 break; 0160 case UPPER_GREEK: 0161 item = toUpperGreek(value); 0162 break; 0163 case HIRAGANA: 0164 item = toHiragana(value); 0165 break; 0166 case HIRAGANA_IROHA: 0167 item = toHiraganaIroha(value); 0168 break; 0169 case KATAKANA: 0170 item = toKatakana(value); 0171 break; 0172 case KATAKANA_IROHA: 0173 item = toKatakanaIroha(value); 0174 break; 0175 // Ideographic: 0176 case JAPANESE_FORMAL: 0177 item = toJapaneseFormal(value); 0178 break; 0179 case JAPANESE_INFORMAL: 0180 item = toJapaneseInformal(value); 0181 break; 0182 case SIMP_CHINESE_FORMAL: 0183 item = toSimpChineseFormal(value); 0184 break; 0185 case SIMP_CHINESE_INFORMAL: 0186 item = toSimpChineseInformal(value); 0187 break; 0188 case TRAD_CHINESE_FORMAL: 0189 item = toTradChineseFormal(value); 0190 break; 0191 case CJK_IDEOGRAPHIC: 0192 // CSS 3 List says treat as trad-chinese-informal 0193 case TRAD_CHINESE_INFORMAL: 0194 item = toTradChineseInformal(value); 0195 break; 0196 default: 0197 item.setNum(value); 0198 break; 0199 } 0200 return item; 0201 } 0202 0203 void RenderCounter::generateContent() 0204 { 0205 bool counters; 0206 counters = !m_counter->separator().isNull(); 0207 0208 if (!m_counterNode) { 0209 m_counterNode = getCounter(m_counter->identifier(), true, counters); 0210 } 0211 0212 int value = m_counterNode->count(); 0213 if (m_counterNode->isReset()) { 0214 value = m_counterNode->value(); 0215 } 0216 int total = value; 0217 if (m_counterNode->parent()) { 0218 total = m_counterNode->parent()->total(); 0219 } 0220 m_item = toListStyleType(value, total, (EListStyleType)m_counter->listStyle()); 0221 0222 if (counters) { 0223 CounterNode *counter = m_counterNode->parent(); 0224 // we deliberately do not render the root counter-node 0225 while (counter->parent() && !(counter->isReset() && counter->parent()->isRoot())) { 0226 value = counter->count(); 0227 total = counter->parent()->total(); 0228 m_item = toListStyleType(value, total, (EListStyleType)m_counter->listStyle()) + m_counter->separator().string() + m_item; 0229 counter = counter->parent(); 0230 }; 0231 } 0232 0233 } 0234 0235 // ------------------------------------------------------------------------- 0236 0237 RenderQuote::RenderQuote(DOM::NodeImpl *node, EQuoteContent type) 0238 : RenderCounterBase(node), m_quoteType(type) 0239 { 0240 } 0241 0242 int RenderQuote::quoteCount() const 0243 { 0244 switch (m_quoteType) { 0245 case OPEN_QUOTE: 0246 case NO_OPEN_QUOTE: 0247 return 1; 0248 case CLOSE_QUOTE: 0249 case NO_CLOSE_QUOTE: 0250 return -1; 0251 case NO_QUOTE: 0252 return 0; 0253 } 0254 assert(false); 0255 return 0; 0256 } 0257 0258 void RenderQuote::generateContent() 0259 { 0260 bool visual; 0261 if (m_quoteType == NO_CLOSE_QUOTE || m_quoteType == NO_OPEN_QUOTE) { 0262 visual = false; 0263 } else { 0264 visual = true; 0265 } 0266 0267 if (!m_counterNode) { 0268 m_counterNode = getCounter("-khtml-quotes", visual, false); 0269 } 0270 0271 int value = m_counterNode->count(); 0272 if (m_counterNode->isReset()) { 0273 value = m_counterNode->value(); 0274 } 0275 switch (m_quoteType) { 0276 case OPEN_QUOTE: 0277 m_item = style()->openQuote(value); 0278 break; 0279 case CLOSE_QUOTE: 0280 m_item = style()->closeQuote(value); 0281 break; 0282 case NO_OPEN_QUOTE: 0283 case NO_CLOSE_QUOTE: 0284 case NO_QUOTE: 0285 m_item.clear(); 0286 } 0287 } 0288 0289 // ------------------------------------------------------------------------- 0290 0291 RenderGlyph::RenderGlyph(DOM::NodeImpl *node, EListStyleType type) 0292 : RenderBox(node), m_type(type) 0293 { 0294 setInline(true); 0295 // setReplaced(true); 0296 } 0297 0298 void RenderGlyph::setStyle(RenderStyle *_style) 0299 { 0300 RenderBox::setStyle(_style); 0301 0302 const QFontMetrics &fm = style()->fontMetrics(); 0303 QRect xSize = fm.boundingRect('x'); 0304 m_height = xSize.height(); 0305 m_width = xSize.width(); 0306 0307 switch (m_type) { 0308 // Glyphs: 0309 case LDISC: 0310 case LCIRCLE: 0311 case LSQUARE: 0312 case LBOX: 0313 case LDIAMOND: 0314 case LNONE: 0315 break; 0316 default: 0317 // not a glyph ! 0318 assert(false); 0319 break; 0320 } 0321 } 0322 0323 void RenderGlyph::calcMinMaxWidth() 0324 { 0325 m_minWidth = m_width; 0326 m_maxWidth = m_width; 0327 0328 setMinMaxKnown(); 0329 } 0330 0331 short RenderGlyph::lineHeight(bool /*b*/) const 0332 { 0333 return height(); 0334 } 0335 0336 short RenderGlyph::baselinePosition(bool /*b*/) const 0337 { 0338 return height(); 0339 } 0340 0341 void RenderGlyph::paint(PaintInfo &paintInfo, int _tx, int _ty) 0342 { 0343 if (paintInfo.phase != PaintActionForeground) { 0344 return; 0345 } 0346 0347 if (style()->visibility() != VISIBLE) { 0348 return; 0349 } 0350 0351 _tx += m_x; 0352 _ty += m_y; 0353 0354 if ((_ty > paintInfo.r.bottom()) || (_ty + m_height <= paintInfo.r.top())) { 0355 return; 0356 } 0357 0358 QPainter *p = paintInfo.p; 0359 0360 const QColor color(style()->color()); 0361 p->setPen(color); 0362 0363 int xHeight = m_height; 0364 int bulletWidth = (xHeight + 1) / 2; 0365 int yoff = (xHeight - 1) / 4; 0366 QRect marker(_tx, _ty + yoff, bulletWidth, bulletWidth); 0367 0368 switch (m_type) { 0369 case LDISC: 0370 p->setBrush(color); 0371 p->drawEllipse(marker); 0372 return; 0373 case LCIRCLE: 0374 p->setBrush(Qt::NoBrush); 0375 p->drawEllipse(marker); 0376 return; 0377 case LSQUARE: 0378 p->setBrush(color); 0379 p->drawRect(marker); 0380 return; 0381 case LBOX: 0382 p->setBrush(Qt::NoBrush); 0383 p->drawRect(marker); 0384 return; 0385 case LDIAMOND: { 0386 static QPolygon diamond(4); 0387 int x = marker.x(); 0388 int y = marker.y(); 0389 int s = bulletWidth / 2; 0390 diamond[0] = QPoint(x + s, y); 0391 diamond[1] = QPoint(x + 2 * s, y + s); 0392 diamond[2] = QPoint(x + s, y + 2 * s); 0393 diamond[3] = QPoint(x, y + s); 0394 p->setBrush(color); 0395 p->drawConvexPolygon(diamond.constData(), 4); 0396 return; 0397 } 0398 case LNONE: 0399 return; 0400 default: 0401 // not a glyph 0402 assert(false); 0403 } 0404 } 0405