CString ViewportConfiguration::description() const
{
    TextStream ts;

    ts.startGroup();
    ts << "viewport-configuration " << (void*)this;
    {
        TextStream::GroupScope scope(ts);
        ts << "viewport arguments";
        ts << m_viewportArguments;
    }
    {
        TextStream::GroupScope scope(ts);
        ts << "configuration";
        ts << m_configuration;
    }
    {
        TextStream::GroupScope scope(ts);
        ts << "default configuration";
        ts << m_defaultConfiguration;
    }

    ts.dumpProperty("contentSize", m_contentSize);
    ts.dumpProperty("minimumLayoutSize", m_minimumLayoutSize);
    ts.dumpProperty("computed initial scale", initialScale());
    ts.dumpProperty("computed minimum scale", minimumScale());
    ts.dumpProperty("computed layout size", layoutSize());
    ts.dumpProperty("ignoring horizontal scaling constraints", shouldIgnoreHorizontalScalingConstraints() ? "true" : "false");
    ts.dumpProperty("ignoring vertical scaling constraints", shouldIgnoreVerticalScalingConstraints() ? "true" : "false");
    
    ts.endGroup();

    return ts.release().utf8();
}
CString ViewportConfiguration::description() const
{
    TextStream ts;

    ts << "(viewport-configuration " << (void*)this;
    ts << "\n";
    ts.increaseIndent();
    ts.writeIndent();
    ts << "(viewport arguments";
    ts << m_viewportArguments;
    ts << ")";
    ts.decreaseIndent();

    ts << "\n";
    ts.increaseIndent();
    ts.writeIndent();
    ts << "(configuration";
    ts << m_configuration;
    ts << ")";
    ts.decreaseIndent();

    ts << "\n";
    ts.increaseIndent();
    ts.writeIndent();
    ts << "(default configuration";
    ts << m_defaultConfiguration;
    ts << ")";
    ts.decreaseIndent();

    ts.dumpProperty("contentSize", m_contentSize);
    ts.dumpProperty("minimumLayoutSize", m_minimumLayoutSize);

    ts << "\n";
    ts.increaseIndent();
    ts.writeIndent();
    ts << "(computed initial scale " << initialScale() << ")\n";
    ts.writeIndent();
    ts << "(computed minimum scale " << minimumScale() << ")\n";
    ts.writeIndent();
    ts << "(computed layout size " << layoutSize() << ")\n";
    ts.writeIndent();
    ts << "(ignoring horizontal scaling constraints " << (shouldIgnoreHorizontalScalingConstraints() ? "true" : "false") << ")\n";
    ts.writeIndent();
    ts << "(ignoring vertical scaling constraints " << (shouldIgnoreVerticalScalingConstraints() ? "true" : "false") << ")";
    ts.decreaseIndent();

    ts << ")\n";

    return ts.release().utf8();
}
double ViewportConfiguration::initialScaleFromSize(double width, double height, bool shouldIgnoreScalingConstraints) const
{
    ASSERT(!constraintsAreAllRelative(m_configuration));

    // If the document has specified its own initial scale, use it regardless.
    // This is guaranteed to be sanity checked already, so no need for MIN/MAX.
    if (m_configuration.initialScaleIsSet && !shouldIgnoreScalingConstraints)
        return m_configuration.initialScale;

    // If not, it is up to us to determine the initial scale.
    // We want a scale small enough to fit the document width-wise.
    const FloatSize& minimumLayoutSize = m_minimumLayoutSize;
    double initialScale = 0;
    if (width > 0 && !shouldIgnoreVerticalScalingConstraints())
        initialScale = minimumLayoutSize.width() / width;

    // Prevent the initial scale from shrinking to a height smaller than our view's minimum height.
    if (height > 0 && height * initialScale < minimumLayoutSize.height() && !shouldIgnoreHorizontalScalingConstraints())
        initialScale = minimumLayoutSize.height() / height;
    return std::min(std::max(initialScale, shouldIgnoreScalingConstraints ? m_defaultConfiguration.minimumScale : m_configuration.minimumScale), m_configuration.maximumScale);
}
double ViewportConfiguration::minimumScale() const
{
    // If we scale to fit, then this is our minimum scale as well.
    if (!m_configuration.initialScaleIsSet || shouldIgnoreScalingConstraints())
        return initialScale();

    // If not, we still need to sanity check our value.
    double minimumScale = m_configuration.minimumScale;

    const FloatSize& minimumLayoutSize = m_minimumLayoutSize;
    double contentWidth = m_contentSize.width();
    if (contentWidth > 0 && contentWidth * minimumScale < minimumLayoutSize.width() && !shouldIgnoreVerticalScalingConstraints())
        minimumScale = minimumLayoutSize.width() / contentWidth;

    double contentHeight = m_contentSize.height();
    if (contentHeight > 0 && contentHeight * minimumScale < minimumLayoutSize.height() && !shouldIgnoreHorizontalScalingConstraints())
        minimumScale = minimumLayoutSize.height() / contentHeight;

    minimumScale = std::min(std::max(minimumScale, m_configuration.minimumScale), m_configuration.maximumScale);

    return minimumScale;
}
bool ViewportConfiguration::shouldIgnoreScalingConstraints() const
{
    return shouldIgnoreHorizontalScalingConstraints() || shouldIgnoreVerticalScalingConstraints();
}