⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 render_text.cpp

📁 konqueror3 embedded版本, KDE环境下的当家浏览器的嵌入式版本源码包.
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/** * This file is part of the DOM implementation for KDE. * * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org) *           (C) 2000-2003 Dirk Mueller (mueller@kde.org) *           (C) 2003 Apple Computer, Inc. *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB.  If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * *///#define DEBUG_LAYOUT//#define BIDI_DEBUG#ifdef HAVE_CONFIG_H#include <config.h>#endif#include "rendering/render_text.h"#include "rendering/render_canvas.h"#include "rendering/break_lines.h"#include "rendering/render_arena.h"#include "xml/dom_nodeimpl.h"#include "misc/loader.h"#include "misc/helper.h"#include <qbitmap.h>#include <qimage.h>#include <qpainter.h>#include <kdebug.h>#include <kglobal.h>#include <assert.h>#include <limits.h>#include <math.h>#ifdef HAVE_ALLOCA_H// explicitly included for systems that don't provide it in stdlib.h#include <alloca.h>#else#include <stdlib.h>#endifusing namespace khtml;using namespace DOM;#ifndef NDEBUGstatic bool inInlineTextBoxDetach;#endifvoid InlineTextBox::detach(RenderArena* renderArena){    if (m_parent)        m_parent->removeFromLine(this);#ifndef NDEBUG    inInlineTextBoxDetach = true;#endif    delete this;#ifndef NDEBUG    inInlineTextBoxDetach = false;#endif    // Recover the size left there for us by operator delete and free the memory.    renderArena->free(*(size_t *)this, this);}void* InlineTextBox::operator new(size_t sz, RenderArena* renderArena) throw(){    return renderArena->allocate(sz);}void InlineTextBox::operator delete(void* ptr, size_t sz){    assert(inInlineTextBoxDetach);    // Stash size where detach can find it.    *(size_t *)ptr = sz;}/** returns the proper ::selection pseudo style for the given element * @return the style or 0 if no ::selection pseudo applies. */inline const RenderStyle *retrieveSelectionPseudoStyle(const RenderObject *obj){  // http://www.w3.org/Style/CSS/Test/CSS3/Selectors/20021129/html/tests/css3-modsel-162.html  // is of the opinion that ::selection of parent elements is also to be applied  // to children, so let's do it.  while (obj) {    const RenderStyle *style = obj->style()->getPseudoStyle(RenderStyle::SELECTION);    if (style) return style;    obj = obj->parent();  }/*wend*/  return 0;}void InlineTextBox::paintSelection(const Font *f, RenderText *text, QPainter *p, RenderStyle* style, int tx, int ty, int startPos, int endPos, int deco){    if(startPos > m_len) return;    if(startPos < 0) startPos = 0;    QColor hc;    QColor hbg;    const RenderStyle* pseudoStyle = retrieveSelectionPseudoStyle(text);    if (pseudoStyle) {        // ### support outline (mandated by CSS3)	// ### support background-image? (optional by CSS3)        if (pseudoStyle->backgroundColor().isValid())            hbg = pseudoStyle->backgroundColor();        hc = pseudoStyle->color();    } else {        const QColorGroup &grp = style->palette().active();        hc = grp.highlightedText();        hbg = grp.highlight();	// ### should be at most retrieved once per render text	QColor bg = khtml::retrieveBackgroundColor(text);	// It may happen that the contrast is -- well -- virtually non existent.	// In this case, simply invert the colors	if (!khtml::hasSufficientContrast(hbg, bg)) {	    hc = QColor(0xff-hc.red(),0xff-hc.green(),0xff-hc.blue());	    hbg = QColor(0xff-hbg.red(),0xff-hbg.green(),0xff-hbg.blue());	}/*end if*/    }    p->setPen(hc);    //kdDebug( 6040 ) << "textRun::painting(" << QConstString(text->str->s + m_start, m_len).string().left(30) << ") at(" << m_x+tx << "/" << m_y+ty << ")" << endl;    f->drawText(p, m_x + tx, m_y + ty + m_baseline, text->str->s, text->str->l,    		m_start, m_len, m_toAdd,		m_reversed ? QPainter::RTL : QPainter::LTR,		startPos, endPos, hbg, m_y + ty, height(), deco);}void InlineTextBox::paintDecoration( QPainter *pt, const Font *f, int _tx, int _ty, int deco){    _tx += m_x;    _ty += m_y;    int width = m_width - 1;    RenderObject *p = object();    QColor underline, overline, linethrough;    p->getTextDecorationColors(deco, underline, overline, linethrough, p->style()->htmlHacks());    if(deco & UNDERLINE){        pt->setPen(underline);        f->drawDecoration(pt, _tx, _ty, baseline(), width, height(), Font::UNDERLINE);    }    if (deco & OVERLINE) {        pt->setPen(overline);        f->drawDecoration(pt, _tx, _ty, baseline(), width, height(), Font::OVERLINE);    }    if(deco & LINE_THROUGH) {        pt->setPen(linethrough);        f->drawDecoration(pt, _tx, _ty, baseline(), width, height(), Font::LINE_THROUGH);    }    // NO! Do NOT add BLINK! It is the most annouing feature of Netscape, and IE has a reason not to    // support it. Lars}void InlineTextBox::paintShadow(QPainter *pt, const Font *f, int _tx, int _ty, const ShadowData *shadow ){    int x = m_x + _tx + shadow->x;    int y = m_y + _ty + shadow->y;    const RenderText* text = renderText();    if (shadow->blur <= 0) {        QColor c = pt->pen().color();        pt->setPen(shadow->color);        f->drawText(pt, x, y+m_baseline, text->str->s, text->str->l,                    m_start, m_len, m_toAdd,                    m_reversed ? QPainter::RTL : QPainter::LTR);        pt->setPen(c);    }    else {        const int thickness = shadow->blur;        const int w = m_width+2*thickness;        const int h = m_height+2*thickness;        const QRgb color = shadow->color.rgb();        const int gray = qGray(color);        const bool inverse = (gray < 100);        const QRgb bgColor = (inverse) ? qRgb(255,255,255) : qRgb(0,0,0);        QPixmap pixmap(w, h);        pixmap.fill(bgColor);        QPainter p;        p.begin(&pixmap);        p.setPen(shadow->color);        p.setFont(pt->font());        f->drawText(&p, thickness, thickness+m_baseline, text->str->s, text->str->l,                    m_start, m_len, m_toAdd,                    m_reversed ? QPainter::RTL : QPainter::LTR);        p.end();        QImage img = pixmap.convertToImage().convertDepth(32);        int md = thickness*thickness; // max-dist^2        // blur map (division cache)        float *bmap = (float*)alloca(sizeof(float)*(md+1));        for(int n=0; n<=md; n++) {            float f;            f = n/(float)(md+1);            f = 1.0 - f*f;            bmap[n] = f;        }        float factor = 0.0; // maximal opacity-sum        for(int n=-thickness; n<=thickness; n++)            for(int m=-thickness; m<=thickness; m++) {                int d = n*n+m*m;                if (d<=md)                    factor += bmap[d];            }        factor = 1.0/factor;        // alpha map        float* amap = (float*)alloca(sizeof(float)*(h*w));        memset(amap, 0, h*w*(sizeof(float)));        for(int j=thickness; j<h-thickness; j++) {            for(int i=thickness; i<w-thickness; i++) {                QRgb col= img.pixel(i,j);                if (col == bgColor) continue;                float g = qGray(col);                if (inverse)                    g = (255-g)/(255-gray);                else                    g = g/gray;                for(int n=-thickness; n<=thickness; n++) {                    for(int m=-thickness; m<=thickness; m++) {                        int d = n*n+m*m;                        if (d>md) continue;                        float f = bmap[d];                        amap[(i+m)+(j+n)*w] += (g*f);                    }                }            }        }        QImage res(w,h,32);        res.setAlphaBuffer(true);        int r = qRed(color);        int g = qGreen(color);        int b = qBlue(color);        for(int j=0; j<h; j++) {            for(int i=0; i<w; i++) {                res.setPixel(i,j, qRgba(r,g,b,(int)(amap[i+j*w]*factor*255.0)));            }        }        pt->drawImage(x-thickness, y-thickness, res, 0, 0, -1, -1, Qt::DiffuseAlphaDither | Qt::ColorOnly | Qt::PreferDither);    }    // Paint next shadow effect    if (shadow->next) paintShadow(pt, f, _tx, _ty, shadow->next);}/** * Distributes pixels to justify text. * @param numSpaces spaces left, will be decremented by one * @param toAdd number of pixels left to be distributed, will have the *	amount of pixels distributed during this call subtracted. * @return number of pixels to distribute */static inline int justifyWidth(int &numSpaces, int &toAdd) {  int a = 0;  if ( numSpaces ) {    a = toAdd/numSpaces;    toAdd -= a;    numSpaces--;  }/*end if*/  return a;}FindSelectionResult InlineTextBox::checkSelectionPoint(int _x, int _y, int _tx, int _ty, const Font *f, RenderText *text, int & offset, short lineHeight){//       kdDebug(6040) << "InlineTextBox::checkSelectionPoint " << this << " _x=" << _x << " _y=" << _y//                     << " _tx+m_x=" << _tx+m_x << " _ty+m_y=" << _ty+m_y << endl;    offset = 0;    if ( _y < _ty + m_y )        return SelectionPointBefore; // above -> before    if ( _y > _ty + m_y + lineHeight ) {        // below -> after        // Set the offset to the max        offset = m_len;        return SelectionPointAfter;    }    if ( _x > _tx + m_x + m_width ) {	// to the right	return m_reversed ? SelectionPointBeforeInLine : SelectionPointAfterInLine;    }    // The Y matches, check if we're on the left    if ( _x < _tx + m_x ) {        return m_reversed ? SelectionPointAfterInLine : SelectionPointBeforeInLine;    }    // consider spacing for justified text    int toAdd = m_toAdd;    bool justified = text->style()->textAlign() == JUSTIFY && toAdd > 0;    int numSpaces = 0;    if (justified) {        for( int i = 0; i < m_len; i++ )            if ( text->str->s[m_start+i].category() == QChar::Separator_Space )	        numSpaces++;    }/*end if*/    int delta = _x - (_tx + m_x);    //kdDebug(6040) << "InlineTextBox::checkSelectionPoint delta=" << delta << endl;    int pos = 0;    if ( m_reversed ) {	delta -= m_width;	while(pos < m_len) {	    int w = f->width( text->str->s, text->str->l, m_start + pos);	    if (justified && text->str->s[m_start + pos].category() == QChar::Separator_Space)	        w += justifyWidth(numSpaces, toAdd);	    int w2 = w/2;	    w -= w2;	    delta += w2;	    if(delta >= 0) break;	    pos++;	    delta += w;	}    } else {	while(pos < m_len) {	    int w = f->width( text->str->s, text->str->l, m_start + pos);	    if (justified && text->str->s[m_start + pos].category() == QChar::Separator_Space)	        w += justifyWidth(numSpaces, toAdd);	    int w2 = w/2;	    w -= w2;	    delta -= w2;	    if(delta <= 0) break;	    pos++;	    delta -= w;	}    }//     kdDebug( 6040 ) << " Text  --> inside at position " << pos << endl;    offset = pos;    return SelectionPointInside;}int InlineTextBox::offsetForPoint(int _x, int &ax) const{  // Do binary search for finding out offset, saves some time for long  // runs.  int start = 0;  int end = m_len;  ax = m_x;  int offset = (start + end) / 2;  while (end - start > 0) {    // always snap to the right column. This makes up for "jumpy" vertical    // navigation.    if (end - start == 1) start = end;    offset = (start + end) / 2;    ax = m_x + widthFromStart(offset);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -