📄 kwqkhtmlpart.cpp
字号:
// Parallel arrays that we use to cache regExps. In practice the number of expressions
// that the app will use is equal to the number of locales is used in searching.
static const unsigned int regExpCacheSize = 4;
static NSMutableArray *regExpLabels = nil;
static QPtrList <QRegExp> regExps;
static QRegExp wordRegExp = QRegExp("\\w");
QRegExp *result;
if (!regExpLabels) {
regExpLabels = [[NSMutableArray alloc] initWithCapacity:regExpCacheSize];
}
unsigned int cacheHit = [regExpLabels indexOfObject:labels];
if (cacheHit != NSNotFound) {
result = regExps.at(cacheHit);
} else {
QString pattern("(");
unsigned int numLabels = [labels count];
unsigned int i;
for (i = 0; i < numLabels; i++) {
QString label = QString::fromNSString([labels objectAtIndex:i]);
bool startsWithWordChar = false;
bool endsWithWordChar = false;
if (label.length() != 0) {
startsWithWordChar = wordRegExp.search(label.at(0)) >= 0;
endsWithWordChar = wordRegExp.search(label.at(label.length() - 1)) >= 0;
}
if (i != 0) {
pattern.append("|");
}
// Search for word boundaries only if label starts/ends with "word characters".
// If we always searched for word boundaries, this wouldn't work for languages
// such as Japanese.
if (startsWithWordChar) {
pattern.append("\\b");
}
pattern.append(label);
if (endsWithWordChar) {
pattern.append("\\b");
}
}
pattern.append(")");
result = new QRegExp(pattern, false);
}
// add regexp to the cache, making sure it is at the front for LRU ordering
if (cacheHit != 0) {
if (cacheHit != NSNotFound) {
// remove from old spot
[regExpLabels removeObjectAtIndex:cacheHit];
regExps.remove(cacheHit);
}
// add to start
[regExpLabels insertObject:labels atIndex:0];
regExps.insert(0, result);
// trim if too big
if ([regExpLabels count] > regExpCacheSize) {
[regExpLabels removeObjectAtIndex:regExpCacheSize];
QRegExp *last = regExps.last();
regExps.removeLast();
delete last;
}
}
return result;
}
NSString *KWQKHTMLPart::searchForLabelsAboveCell(QRegExp *regExp, HTMLTableCellElementImpl *cell)
{
RenderTableCell *cellRenderer = static_cast<RenderTableCell *>(cell->renderer());
RenderTableCell *cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer);
if (cellAboveRenderer) {
HTMLTableCellElementImpl *aboveCell =
static_cast<HTMLTableCellElementImpl *>(cellAboveRenderer->element());
if (aboveCell) {
// search within the above cell we found for a match
for (NodeImpl *n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
if (idFromNode(n) == ID_TEXT
&& n->renderer() && n->renderer()->style()->visibility() == VISIBLE)
{
// For each text chunk, run the regexp
QString nodeString = n->nodeValue().string();
int pos = regExp->searchRev(nodeString);
if (pos >= 0) {
return nodeString.mid(pos, regExp->matchedLength()).getNSString();
}
}
}
}
}
// Any reason in practice to search all cells in that are above cell?
return nil;
}
NSString *KWQKHTMLPart::searchForLabelsBeforeElement(NSArray *labels, ElementImpl *element)
{
QRegExp *regExp = regExpForLabels(labels);
// We stop searching after we've seen this many chars
const unsigned int charsSearchedThreshold = 500;
// This is the absolute max we search. We allow a little more slop than
// charsSearchedThreshold, to make it more likely that we'll search whole nodes.
const unsigned int maxCharsSearched = 600;
// If the starting element is within a table, the cell that contains it
HTMLTableCellElementImpl *startingTableCell = 0;
bool searchedCellAbove = false;
// walk backwards in the node tree, until another element, or form, or end of tree
int unsigned lengthSearched = 0;
NodeImpl *n;
for (n = element->traversePreviousNode();
n && lengthSearched < charsSearchedThreshold;
n = n->traversePreviousNode())
{
NodeImpl::Id nodeID = idFromNode(n);
if (nodeID == ID_FORM
|| (n->isHTMLElement()
&& static_cast<HTMLElementImpl *>(n)->isGenericFormElement()))
{
// We hit another form element or the start of the form - bail out
break;
} else if (nodeID == ID_TD && !startingTableCell) {
startingTableCell = static_cast<HTMLTableCellElementImpl *>(n);
} else if (nodeID == ID_TR && startingTableCell) {
NSString *result = searchForLabelsAboveCell(regExp, startingTableCell);
if (result) {
return result;
}
searchedCellAbove = true;
} else if (nodeID == ID_TEXT
&& n->renderer() && n->renderer()->style()->visibility() == VISIBLE)
{
// For each text chunk, run the regexp
QString nodeString = n->nodeValue().string();
// add 100 for slop, to make it more likely that we'll search whole nodes
if (lengthSearched + nodeString.length() > maxCharsSearched) {
nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
}
int pos = regExp->searchRev(nodeString);
if (pos >= 0) {
return nodeString.mid(pos, regExp->matchedLength()).getNSString();
} else {
lengthSearched += nodeString.length();
}
}
}
// If we started in a cell, but bailed because we found the start of the form or the
// previous element, we still might need to search the row above us for a label.
if (startingTableCell && !searchedCellAbove) {
return searchForLabelsAboveCell(regExp, startingTableCell);
} else {
return nil;
}
}
NSString *KWQKHTMLPart::matchLabelsAgainstElement(NSArray *labels, ElementImpl *element)
{
QString name = element->getAttribute(ATTR_NAME).string();
// Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
name.replace(QRegExp("[[:digit:]]"), " ");
name.replace('_', ' ');
QRegExp *regExp = regExpForLabels(labels);
// Use the largest match we can find in the whole name string
int pos;
int length;
int bestPos = -1;
int bestLength = -1;
int start = 0;
do {
pos = regExp->search(name, start);
if (pos != -1) {
length = regExp->matchedLength();
if (length >= bestLength) {
bestPos = pos;
bestLength = length;
}
start = pos+1;
}
} while (pos != -1);
if (bestPos != -1) {
return name.mid(bestPos, bestLength).getNSString();
} else {
return nil;
}
}
#endif
void KWQKHTMLPart::ClearFind()
{
// need implementation
//view()->calcContentPosition(0, 0, INT_MAX, true, true, bool foundInOrigView, QPoint &aToPoint)
const khtml::Selection noSelection;
setSelection(noSelection, false);
d->m_firstFound = noSelection;
}
TInt KWQKHTMLPart::FindStringAgain(const TDesC& str, TBool forward, TBool caseSensitive, TBool wrap)
{
// update the the first found selection when user issue a findagain.
// the first found selection is cleared whenever user is changing the
// keyword.
if (d->m_firstFound.toRange().collapsed())
{
d->m_firstFound = d->m_selection;
}
return FindString(str, forward, caseSensitive, wrap, true);
}
// Search from the end of the currently selected location if we are first responder, or from
// the beginning of the document if nothing is selected or we're not first responder.
TInt KWQKHTMLPart::FindString(const TDesC& str, TBool forward, TBool caseSensitive, TBool wrap, TBool sameStr)
{
TInt result = TBrCtlDefs::EFindNoMatches;
QString target = QString::FromDes(str);
if (target.isEmpty())
{
ClearFind();
return result;
}
if (!sameStr )
{
// clear the first found when keyword changes, set it when a findAgain is invoked
d->m_firstFound = khtml::Selection();
}
// Start on the correct edge of the selection, search to edge of document.
Range searchRange(xmlDocImpl());
searchRange.selectNodeContents(xmlDocImpl());
if (d->m_lastFound.start().node()) {
NodeImpl * lastStartNode = d->m_lastFound.start().node();
NodeImpl * lastEndNode = d->m_lastFound.end().node();
int lastStartOffset = d->m_lastFound.start().offset();
int lastEndOffset = d->m_lastFound.end().offset();
if (forward)
if (sameStr)
searchRange.setStart(lastEndNode, lastEndOffset);
else
searchRange.setStart(lastStartNode, lastStartOffset);
else
if (sameStr)
searchRange.setEnd(lastStartNode, lastStartOffset);
else
searchRange.setEnd(lastEndNode, lastEndOffset);
}
// Do the search once, then do it a second time to handle wrapped search.
// Searches some or all of document twice in the failure case, but that's probably OK.
Range resultRange = khtml::findPlainText(searchRange, target, forward, caseSensitive);
if (resultRange.collapsed() && wrap) {
result = TBrCtlDefs::EFindWrapAround;
searchRange.selectNodeContents(xmlDocImpl());
resultRange = khtml::findPlainText(searchRange, target, forward, caseSensitive);
}
if (resultRange.collapsed()) {
ClearFind();
return TBrCtlDefs::EFindNoMatches;
}
else
{
if (result != TBrCtlDefs::EFindWrapAround)
result = TBrCtlDefs::EFindMatch;
// If we got back to the same place we started, that means we found all matches.
if (resultRange == d->m_firstFound.toRange())
{
result = TBrCtlDefs::EFindAllMatches;
// if the selection is the only occurance in the search range, no need to update.
if (resultRange == selection().toRange()) {
return result;
}
}
}
setSelection(khtml::Selection(resultRange, khtml::DOWNSTREAM, khtml::SEL_PREFER_UPSTREAM_AFFINITY), false);
d->m_lastFound = d->m_selection;
//jumpToSelection();
return result;
}
void KWQKHTMLPart::clearRecordedFormValues()
{
// ### NOT IMPLEMENTED forms
/*
// It's safe to assume that our own classes and Foundation data
// structures won't raise exceptions in dealloc
KWQRelease(_formValuesAboutToBeSubmitted);
_formValuesAboutToBeSubmitted = nil;
KWQRelease(_formAboutToBeSubmitted);
_formAboutToBeSubmitted = nil;
*/
}
void KWQKHTMLPart::recordFormValue(const QString &name, const QString &value, HTMLFormElementImpl *element)
{
// ### NOT IMPLEMENTED forms
/*
// It's safe to assume that our own classes and basic Foundation
// data structures won't raise exceptions
if (!_formValuesAboutToBeSubmitted) {
_formValuesAboutToBeSubmitted = KWQRetainNSRelease([[NSMutableDictionary alloc] init]);
ASSERT(!_formAboutToBeSubmitted);
_formAboutToBeSubmitted = KWQRetain([DOMElement _elementWithImpl:element]);
} else {
ASSERT([_formAboutToBeSubmitted _elementImpl] == element);
}
[_formValuesAboutToBeSubmitted setObject:value.getNSString() forKey:name.getNSString()];
*/
}
void KWQKHTMLPart::submitForm(const KURL &url, const URLArgs &args)
{
// ### NOT IMPLEMENTED forms
/*
KWQ_BLOCK_EXCEPTIONS;
// The form multi-submit logic here is only right when we are submitting a form that affects this frame.
// Eventually when we find a better fix we can remove this altogether.
WebCoreBridge *target = args.frameName.isEmpty() ? _bridge : [_bridge findFrameNamed:args.frameName.getNSString()];
KHTMLPart *targetPart = [target part];
bool willReplaceThisFrame = false;
for (KHTMLPart *p = this; p; p = p->parentPart()) {
if (p == targetPart) {
willReplaceThisFrame = true;
break;
}
}
if (willReplaceThisFrame) {
if (_submittedFormURL == url) {
return;
}
_submittedFormURL = url;
}*/
if (!args.doPost()) {
TEventCode code = EEventNull;
_bridge->Client().LoadUrl(url.Des(),
_bridge->Referrer(), // referrer
args.reload, // reload
ETrue, //userGesture
args.frameName.Des(), //target
code //triggeringEvent
);
} else {
TEventCode code( EEventNull );
ASSERT(args.contentType().startsWith("Content-Type: "));
RArray<TWebCoreFormDataItem> formData;
WebCoreFromFormData(args.postData, formData);
_bridge->Client().PostWithURL( url.Des(),
_bridge->Referrer(), // referrer
args.frameName.Des(), //target
formData, // post data
args.contentType().mid(14).Des(),
code );
formData.Close();
}
// clearRecordedFormValues();
// KWQ_UNBLOCK_EXCEPTIONS;
}
void KWQKHTMLPart::setEncoding(const QString &name, bool userChosen)
{
if (!d->m_workingURL.isEmpty()) {
receivedFirstData();
}
d->m_encoding = name;
d->m_haveEncoding = userChosen;
}
void KWQKHTMLPart::addData(const char *bytes, int length)
{
ASSERT(d->m_workingURL.isEmpty());
ASSERT(d->m_doc);
ASSERT(d->m_doc->parsing());
write(bytes, length);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -