bool DOMImplementation::hasFeature(const String& feature, const String& version)
{
    String lower = feature.lower();
    if (lower == "core" || lower == "html" || lower == "xml" || lower == "xhtml")
        return version.isEmpty() || version == "1.0" || version == "2.0";
    if (lower == "css"
            || lower == "css2"
            || lower == "events"
            || lower == "htmlevents"
            || lower == "mouseevents"
            || lower == "mutationevents"
            || lower == "range"
            || lower == "stylesheets"
            || lower == "traversal"
            || lower == "uievents"
            || lower == "views")
        return version.isEmpty() || version == "2.0";
    if (lower == "xpath" || lower == "textevents")
        return version.isEmpty() || version == "3.0";

#if ENABLE(SVG)
    if ((version.isEmpty() || version == "1.1") && feature.startsWith("http://www.w3.org/tr/svg11/feature#", false)) {
        if (isSVG11Feature(feature.right(feature.length() - 35)))
            return true;
    }

    if ((version.isEmpty() || version == "1.0") && feature.startsWith("org.w3c.", false)) {
        if (isSVG10Feature(feature.right(feature.length() - 8)))
            return true;
    }
#endif
    
    return false;
}
Example #2
0
PassRefPtr<SecurityOrigin> SecurityOrigin::createFromDatabaseIdentifier(const String& databaseIdentifier)
{ 
    // Make sure there's a first separator
    int separator1 = databaseIdentifier.find(SeparatorCharacter);
    if (separator1 == -1)
        return create(KURL());
        
    // Make sure there's a second separator
    int separator2 = databaseIdentifier.find(SeparatorCharacter, separator1 + 1);
    if (separator2 == -1)
        return create(KURL());
        
    // Make sure there's not a third separator
    if (databaseIdentifier.reverseFind(SeparatorCharacter) != separator2)
        return create(KURL());
        
    // Make sure the port section is a valid port number or doesn't exist
    bool portOkay;
    int port = databaseIdentifier.right(databaseIdentifier.length() - separator2 - 1).toInt(&portOkay);
    if (!portOkay && separator2 + 1 == static_cast<int>(databaseIdentifier.length()))
        return create(KURL());
    
    if (port < 0 || port > 65535)
        return create(KURL());
        
    // Split out the 3 sections of data
    String protocol = databaseIdentifier.substring(0, separator1);
    String host = databaseIdentifier.substring(separator1 + 1, separator2 - separator1 - 1);
    return create(KURL(KURL(), protocol + "://" + host + ":" + String::number(port)));
}
Example #3
0
void SessionRep::extract(
    const String& arg, const OptionDesc& o, int& i, int argc, char** argv,
    String& name, String& value
) {
    int colon;
    switch (o.style) {
    case OptionPropertyNext:
	value = next_arg(i, argc, argv, "missing property after '%s'", arg);
	colon = value.index(':');
	if (colon < 0) {
	    bad_arg("missing ':' in '%s'", value);
	} else {
	    name = value.left(colon);
	    value = value.right(colon+1);
	}
	break;
    case OptionValueNext:
	name = o.path;
	value = next_arg(i, argc, argv, "missing value after '%s'", arg);
	break;
    case OptionValueImplicit:
	name = o.path;
	value = o.value;
	break;
    case OptionValueIsArg:
	name = o.path;
	value = arg;
	break;
    case OptionValueAfter:
	bad_arg("missing value in '%s'", arg);
	break;
    }
}
static bool isSupportedSVG10Feature(const String& feature, const String& version)
{
    if (!version.isEmpty() && version != "1.0")
        return false;

#if !PLATFORM(WKC)
    static bool initialized = false;
#else
    WKC_DEFINE_STATIC_BOOL(initialized, false);
#endif
    DEPRECATED_DEFINE_STATIC_LOCAL(FeatureSet, svgFeatures, ());
    if (!initialized) {
#if ENABLE(SVG_FONTS)
        addString(svgFeatures, "svg");
        addString(svgFeatures, "svg.static");
#endif
//      addString(svgFeatures, "svg.animation");
//      addString(svgFeatures, "svg.dynamic");
//      addString(svgFeatures, "svg.dom.animation");
//      addString(svgFeatures, "svg.dom.dynamic");
#if ENABLE(SVG_FONTS)
        addString(svgFeatures, "dom");
        addString(svgFeatures, "dom.svg");
        addString(svgFeatures, "dom.svg.static");
#endif
//      addString(svgFeatures, "svg.all");
//      addString(svgFeatures, "dom.svg.all");
        initialized = true;
    }
    return feature.startsWith("org.w3c.", false)
        && svgFeatures.contains(feature.right(feature.length() - 8));
}
PassRefPtr<SecurityOrigin> SecurityOrigin::maybeCreateFromDatabaseIdentifier(const String& databaseIdentifier)
{ 
    // Make sure there's a first separator
    size_t separator1 = databaseIdentifier.find(separatorCharacter);
    if (separator1 == notFound)
        return nullptr;
        
    // Make sure there's a second separator
    size_t separator2 = databaseIdentifier.reverseFind(separatorCharacter);
    if (separator2 == notFound)
        return nullptr;

    // Ensure there were at least 2 separator characters. Some hostnames on intranets have
    // underscores in them, so we'll assume that any additional underscores are part of the host.
    if (separator1 == separator2)
        return nullptr;

    // Make sure the port section is a valid port number or doesn't exist
    bool portOkay;
    int port = databaseIdentifier.right(databaseIdentifier.length() - separator2 - 1).toInt(&portOkay);
    bool portAbsent = (separator2 == databaseIdentifier.length() - 1);
    if (!(portOkay || portAbsent))
        return nullptr;

    if (port < 0 || port > MaxAllowedPort)
        return nullptr;

    // Split out the 3 sections of data
    String protocol = databaseIdentifier.substring(0, separator1);
    String host = databaseIdentifier.substring(separator1 + 1, separator2 - separator1 - 1);
    
    host = decodeURLEscapeSequences(host);
    return create(URL(URL(), protocol + "://" + host + ":" + String::number(port) + "/"));
}
Example #6
0
void FindInFilesPanel::apply_replaces_in_file(String fpath, PoolIntArray locations, String text) {

	ERR_FAIL_COND(locations.size() % 3 != 0);

	//print_line(String("Replacing {0} occurrences in {1}").format(varray(fpath, locations.size() / 3)));

	// If the file is already open, I assume the editor will reload it.
	// If there are unsaved changes, the user will be asked on focus,
	// however that means either loosing changes or loosing replaces.

	FileAccess *f = FileAccess::open(fpath, FileAccess::READ);
	ERR_FAIL_COND(f == NULL);

	String buffer;
	int current_line = 1;

	ConservativeGetLine conservative;

	String line = conservative.get_line(f);

	PoolIntArray::Read locations_read = locations.read();
	for (int i = 0; i < locations.size(); i += 3) {

		int repl_line_number = locations_read[i];
		int repl_begin = locations_read[i + 1];
		int repl_end = locations_read[i + 2];

		while (current_line < repl_line_number) {
			buffer += line;
			line = conservative.get_line(f);
			++current_line;
		}

		line = line.left(repl_begin) + text + line.right(repl_end);
	}

	buffer += line;

	while (!f->eof_reached()) {
		buffer += conservative.get_line(f);
	}

	// Now the modified contents are in the buffer, rewrite the file with our changes

	Error err = f->reopen(fpath, FileAccess::WRITE);
	ERR_FAIL_COND(err != OK);

	f->store_string(buffer);

	f->close();
}
bool UserContentURLPattern::parse(const String& pattern)
{
    static NeverDestroyed<const String> schemeSeparator(ASCIILiteral("://"));

    size_t schemeEndPos = pattern.find(schemeSeparator);
    if (schemeEndPos == notFound)
        return false;

    m_scheme = pattern.left(schemeEndPos);

    unsigned hostStartPos = schemeEndPos + schemeSeparator.get().length();
    if (hostStartPos >= pattern.length())
        return false;

    int pathStartPos = 0;

    if (equalLettersIgnoringASCIICase(m_scheme, "file"))
        pathStartPos = hostStartPos;
    else {
        size_t hostEndPos = pattern.find('/', hostStartPos);
        if (hostEndPos == notFound)
            return false;

        m_host = pattern.substring(hostStartPos, hostEndPos - hostStartPos);
        m_matchSubdomains = false;

        if (m_host == "*") {
            // The pattern can be just '*', which means match all domains.
            m_host = emptyString();
            m_matchSubdomains = true;
        } else if (m_host.startsWith("*.")) {
            // The first component can be '*', which means to match all subdomains.
            m_host = m_host.substring(2); // Length of "*."
            m_matchSubdomains = true;
        }

        // No other '*' can occur in the host.
        if (m_host.find('*') != notFound)
            return false;

        pathStartPos = hostEndPos;
    }

    m_path = pattern.right(pattern.length() - pathStartPos);

    return true;
}
Example #8
0
boolean SessionRep::match(
    const String& arg, const OptionDesc& o, int& i, int argc, char** argv
) {
    String opt(o.name);
    if (arg != opt) {
	if (o.style == OptionValueAfter) {
	    int n = opt.length();
	    if (opt == arg.left(n)) {
		style_->attribute(String(o.path), arg.right(n));
		return true;
	    }
	}
	return false;
    }
    String name, value;
    extract(arg, o, i, argc, argv, name, value);
    style_->attribute(name, value);
    return true;
}
PassRefPtr<SecurityOrigin> createSecurityOriginFromDatabaseIdentifier(const String& databaseIdentifier)
{
    if (!databaseIdentifier.containsOnlyASCII())
        return SecurityOrigin::createUnique();

    // Make sure there's a first separator
    size_t separator1 = databaseIdentifier.find(separatorCharacter);
    if (separator1 == notFound)
        return SecurityOrigin::createUnique();

    // Make sure there's a second separator
    size_t separator2 = databaseIdentifier.reverseFind(separatorCharacter);
    if (separator2 == notFound)
        return SecurityOrigin::createUnique();

    // Ensure there were at least 2 separator characters. Some hostnames on intranets have
    // underscores in them, so we'll assume that any additional underscores are part of the host.
    if (separator1 == separator2)
        return SecurityOrigin::createUnique();

    // Make sure the port section is a valid port number or doesn't exist
    bool portOkay;
    int port = databaseIdentifier.right(databaseIdentifier.length() - separator2 - 1).toInt(&portOkay);
    bool portAbsent = (separator2 == databaseIdentifier.length() - 1);
    if (!(portOkay || portAbsent))
        return SecurityOrigin::createUnique();

    if (port < 0 || port > maxAllowedPort)
        return SecurityOrigin::createUnique();

    // Split out the 3 sections of data
    String protocol = databaseIdentifier.substring(0, separator1);
    String host = databaseIdentifier.substring(separator1 + 1, separator2 - separator1 - 1);

    // Make sure the components match their canonical representation so we are sure we're round tripping correctly.
    KURL url(KURL(), protocol + "://" + host + ":" + String::number(port) + "/");
    if (!url.isValid() || url.protocol() != protocol || url.host() != host)
        return SecurityOrigin::createUnique();

    return SecurityOrigin::create(url);
}
Example #10
0
String AbstractInlineTextBox::text() const
{
    if (!m_inlineTextBox || !m_renderText)
        return String();

    unsigned start = m_inlineTextBox->start();
    unsigned len = m_inlineTextBox->len();
    if (Node* node = m_renderText->node()) {
        RefPtrWillBeRawPtr<Range> range = Range::create(node->document());
        range->setStart(node, start, IGNORE_EXCEPTION);
        range->setEnd(node, start + len, IGNORE_EXCEPTION);
        return plainText(range.get(), TextIteratorIgnoresStyleVisibility);
    }

    String result = m_renderText->text().substring(start, len).simplifyWhiteSpace(WTF::DoNotStripWhiteSpace);
    if (m_inlineTextBox->nextTextBox() && m_inlineTextBox->nextTextBox()->start() > m_inlineTextBox->end() && result.length() && !result.right(1).containsOnlyWhitespace())
        return result + " ";
    return result;
}
Example #11
0
static bool isSupportedSVG11Feature(const String& feature, const String& version)
{
    if (!version.isEmpty() && version != "1.1")
        return false;

#if !PLATFORM(WKC)
    static bool initialized = false;
#else
    WKC_DEFINE_STATIC_BOOL(initialized, false);
#endif
    DEPRECATED_DEFINE_STATIC_LOCAL(FeatureSet, svgFeatures, ());
    if (!initialized) {
        // Sadly, we cannot claim to implement any of the SVG 1.1 generic feature sets
        // lack of Font and Filter support.
        // http://bugs.webkit.org/show_bug.cgi?id=15480
#if ENABLE(SVG_FONTS)
        addString(svgFeatures, "SVG");
        addString(svgFeatures, "SVGDOM");
        addString(svgFeatures, "SVG-static");
        addString(svgFeatures, "SVGDOM-static");
#endif
        addString(svgFeatures, "SVG-animation");
        addString(svgFeatures, "SVGDOM-animation");
//      addString(svgFeatures, "SVG-dynamic);
//      addString(svgFeatures, "SVGDOM-dynamic);
        addString(svgFeatures, "CoreAttribute");
        addString(svgFeatures, "Structure");
        addString(svgFeatures, "BasicStructure");
        addString(svgFeatures, "ContainerAttribute");
        addString(svgFeatures, "ConditionalProcessing");
        addString(svgFeatures, "Image");
        addString(svgFeatures, "Style");
        addString(svgFeatures, "ViewportAttribute");
        addString(svgFeatures, "Shape");
        addString(svgFeatures, "Text");
        addString(svgFeatures, "BasicText");
        addString(svgFeatures, "PaintAttribute");
        addString(svgFeatures, "BasicPaintAttribute");
        addString(svgFeatures, "OpacityAttribute");
        addString(svgFeatures, "GraphicsAttribute");
        addString(svgFeatures, "BaseGraphicsAttribute");
        addString(svgFeatures, "Marker");
//      addString(svgFeatures, "ColorProfile"); // requires color-profile, bug 6037
        addString(svgFeatures, "Gradient");
        addString(svgFeatures, "Pattern");
        addString(svgFeatures, "Clip");
        addString(svgFeatures, "BasicClip");
        addString(svgFeatures, "Mask");
        addString(svgFeatures, "Filter");
        addString(svgFeatures, "BasicFilter");
        addString(svgFeatures, "DocumentEventsAttribute");
        addString(svgFeatures, "GraphicalEventsAttribute");
//      addString(svgFeatures, "AnimationEventsAttribute");
        addString(svgFeatures, "Cursor");
        addString(svgFeatures, "Hyperlinking");
        addString(svgFeatures, "XlinkAttribute");
        addString(svgFeatures, "ExternalResourcesRequired");
        addString(svgFeatures, "View");
        addString(svgFeatures, "Script");
        addString(svgFeatures, "Animation"); 
#if ENABLE(SVG_FONTS)
        addString(svgFeatures, "Font");
        addString(svgFeatures, "BasicFont");
#endif
        addString(svgFeatures, "Extensibility");
        initialized = true;
    }
    return feature.startsWith("http://www.w3.org/tr/svg11/feature#", false)
        && svgFeatures.contains(feature.right(feature.length() - 35));
}
Example #12
0
void EditorHelpSearch::_update_search() {

	search_options->clear();
	search_options->set_hide_root(true);

	/*
	TreeItem *root = search_options->create_item();
	_parse_fs(EditorFileSystem::get_singleton()->get_filesystem());
*/

	List<StringName> type_list;
	ObjectTypeDB::get_type_list(&type_list);

	DocData *doc=EditorHelp::get_doc_data();
	String term = search_box->get_text();
	if (term.length()<2)
		return;

	TreeItem *root = search_options->create_item();



	Ref<Texture> def_icon = get_icon("Node","EditorIcons");
	//classes first
	for (Map<String,DocData::ClassDoc>::Element *E=doc->class_list.front();E;E=E->next()) {

		if (E->key().findn(term)!=-1) {

			TreeItem *item = search_options->create_item(root);
			item->set_metadata(0,"class_name:"+E->key());
			item->set_text(0,E->key()+" (Class)");
			if (has_icon(E->key(),"EditorIcons"))
				item->set_icon(0,get_icon(E->key(),"EditorIcons"));
			else
				item->set_icon(0,def_icon);


		}

	}

	//class methods, etc second
	for (Map<String,DocData::ClassDoc>::Element *E=doc->class_list.front();E;E=E->next()) {


		DocData::ClassDoc & c = E->get();

		Ref<Texture> cicon;
		if (has_icon(E->key(),"EditorIcons"))
			cicon=get_icon(E->key(),"EditorIcons");
		else
			cicon=def_icon;


		for(int i=0;i<c.methods.size();i++) {
			if( (term.begins_with(".") && c.methods[i].name.begins_with(term.right(1)))
				|| (term.ends_with("(") && c.methods[i].name.ends_with(term.left(term.length()-1).strip_edges()))
				|| (term.begins_with(".") && term.ends_with("(") && c.methods[i].name==term.substr(1,term.length()-2).strip_edges())
				|| c.methods[i].name.findn(term)!=-1) {

				TreeItem *item = search_options->create_item(root);
				item->set_metadata(0,"class_method:"+E->key()+":"+c.methods[i].name);
				item->set_text(0,E->key()+"."+c.methods[i].name+" (Method)");
				item->set_icon(0,cicon);
			}
		}

		for(int i=0;i<c.signals.size();i++) {

			if (c.signals[i].name.findn(term)!=-1) {

				TreeItem *item = search_options->create_item(root);
				item->set_metadata(0,"class_signal:"+E->key()+":"+c.signals[i].name);
				item->set_text(0,E->key()+"."+c.signals[i].name+" (Signal)");
				item->set_icon(0,cicon);
			}
		}

		for(int i=0;i<c.constants.size();i++) {

			if (c.constants[i].name.findn(term)!=-1) {

				TreeItem *item = search_options->create_item(root);
				item->set_metadata(0,"class_constant:"+E->key()+":"+c.constants[i].name);
				item->set_text(0,E->key()+"."+c.constants[i].name+" (Constant)");
				item->set_icon(0,cicon);
			}
		}

		for(int i=0;i<c.properties.size();i++) {

			if (c.properties[i].name.findn(term)!=-1) {

				TreeItem *item = search_options->create_item(root);
				item->set_metadata(0,"class_property:"+E->key()+":"+c.properties[i].name);
				item->set_text(0,E->key()+"."+c.properties[i].name+" (Property)");
				item->set_icon(0,cicon);
			}
		}

		for(int i=0;i<c.theme_properties.size();i++) {

			if (c.theme_properties[i].name.findn(term)!=-1) {

				TreeItem *item = search_options->create_item(root);
				item->set_metadata(0,"class_theme_item:"+E->key()+":"+c.theme_properties[i].name);
				item->set_text(0,E->key()+"."+c.theme_properties[i].name+" (Theme Item)");
				item->set_icon(0,cicon);
			}
		}


	}

	//same but descriptions

	for (Map<String,DocData::ClassDoc>::Element *E=doc->class_list.front();E;E=E->next()) {


		DocData::ClassDoc & c = E->get();

		Ref<Texture> cicon;
		if (has_icon(E->key(),"EditorIcons"))
			cicon=get_icon(E->key(),"EditorIcons");
		else
			cicon=def_icon;

		if (c.description.findn(term)!=-1) {


			TreeItem *item = search_options->create_item(root);
			item->set_metadata(0,"class_desc:"+E->key());
			item->set_text(0,E->key()+" (Class Description)");
			item->set_icon(0,cicon);

		}

		for(int i=0;i<c.methods.size();i++) {

			if (c.methods[i].description.findn(term)!=-1) {

				TreeItem *item = search_options->create_item(root);
				item->set_metadata(0,"class_method_desc:"+E->key()+":"+c.methods[i].name);
				item->set_text(0,E->key()+"."+c.methods[i].name+" (Method Description)");
				item->set_icon(0,cicon);
			}
		}

		for(int i=0;i<c.signals.size();i++) {

			if (c.signals[i].description.findn(term)!=-1) {

				TreeItem *item = search_options->create_item(root);
				item->set_metadata(0,"class_signal:"+E->key()+":"+c.signals[i].name);
				item->set_text(0,E->key()+"."+c.signals[i].name+" (Signal Description)");
				item->set_icon(0,cicon);
			}
		}

		for(int i=0;i<c.constants.size();i++) {

			if (c.constants[i].description.findn(term)!=-1) {

				TreeItem *item = search_options->create_item(root);
				item->set_metadata(0,"class_constant:"+E->key()+":"+c.constants[i].name);
				item->set_text(0,E->key()+"."+c.constants[i].name+" (Constant Description)");
				item->set_icon(0,cicon);
			}
		}

		for(int i=0;i<c.properties.size();i++) {

			if (c.properties[i].description.findn(term)!=-1) {

				TreeItem *item = search_options->create_item(root);
				item->set_metadata(0,"class_property_desc:"+E->key()+":"+c.properties[i].name);
				item->set_text(0,E->key()+"."+c.properties[i].name+" (Property Description)");
				item->set_icon(0,cicon);
			}
		}

	}

	get_ok()->set_disabled(root->get_children()==NULL);

}
String AbstractInlineTextBox::text() const
{
    if (!m_inlineTextBox || !m_layoutText)
        return String();

    unsigned start = m_inlineTextBox->start();
    unsigned len = m_inlineTextBox->len();
    if (Node* node = m_layoutText->node()) {
        if (node->isTextNode())
            return plainText(Position(node, start), Position(node, start + len), TextIteratorIgnoresStyleVisibility);
        return plainText(Position(node, PositionAnchorType::BeforeAnchor), Position(node, PositionAnchorType::AfterAnchor), TextIteratorIgnoresStyleVisibility);
    }

    String result = m_layoutText->text().substring(start, len).simplifyWhiteSpace(WTF::DoNotStripWhiteSpace);
    if (m_inlineTextBox->nextTextBox() && m_inlineTextBox->nextTextBox()->start() > m_inlineTextBox->end() && result.length() && !result.right(1).containsOnlyWhitespace())
        return result + " ";
    return result;
}
Example #14
0
void FindInFilesDialog::_on_folder_selected(String path) {
	int i = path.find("://");
	if (i != -1)
		path = path.right(i + 3);
	_folder_line_edit->set_text(path);
}
Example #15
0
String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove)
{
    OwnPtr<RegularExpression> regExp(createRegExpForLabels(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
    HTMLTableCellElement* startingTableCell = 0;
    bool searchedCellAbove = false;

    if (resultDistance)
        *resultDistance = notFound;
    if (resultIsInCellAbove)
        *resultIsInCellAbove = false;

    // walk backwards in the node tree, until another element, or form, or end of tree
    int unsigned lengthSearched = 0;
    Node* n;
    for (n = element->traversePreviousNode();
            n && lengthSearched < charsSearchedThreshold;
            n = n->traversePreviousNode())
    {
        if (n->hasTagName(formTag)
                || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()))
        {
            // We hit another form element or the start of the form - bail out
            break;
        } else if (n->hasTagName(tdTag) && !startingTableCell) {
            startingTableCell = static_cast<HTMLTableCellElement*>(n);
        } else if (n->hasTagName(trTag) && startingTableCell) {
            String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
            if (!result.isEmpty()) {
                if (resultIsInCellAbove)
                    *resultIsInCellAbove = true;
                return result;
            }
            searchedCellAbove = true;
        } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
            // For each text chunk, run the regexp
            String nodeString = n->nodeValue();
            // 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) {
                if (resultDistance)
                    *resultDistance = lengthSearched;
                return nodeString.substring(pos, regExp->matchedLength());
            }
            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) {
        String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
        if (!result.isEmpty()) {
            if (resultIsInCellAbove)
                *resultIsInCellAbove = true;
            return result;
        }
    }
    return String();
}