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