void
UIRenderer::render(uint32_t count, uint32_t vertexOffset)
{
    _vertexOffset = vertexOffset;
    // Count is index or vertex count depending on indexed or not. Convert.
    const Ibl::IShader* shader = material()->shader();

    if (primitiveType() == Ibl::TriangleList)
    {
        _primitiveCount = count / 3;
    }
    else if (primitiveType() == Ibl::TriangleStrip)
    {
        _primitiveCount = (count-2);
    }

    const Ibl::GpuVariable* viewProjVariable = nullptr;
    if (shader->getParameterByName("u_viewProj", viewProjVariable))
        viewProjVariable->setMatrix(&_viewProj._m[0][0]);

    const Ibl::GpuVariable* viewTexelVariable = nullptr;
    if (shader->getParameterByName("u_viewTexel", viewTexelVariable))
    {
        Ibl::Vector4f viewTexel = Ibl::Vector4f(1.0f / _device->backbuffer()->width(), 
                                                1.0f / _device->backbuffer()->height(), 0,0);
        viewTexelVariable->setVector(&viewTexel.x);
    }


    // Try to setup ortho if it is available.
    shader->renderMesh (Ibl::RenderRequest(material()->technique(), nullptr, nullptr, this));
}
    virtual void render(bool use_vbo) const
    {
      VL_CHECK(GLEW_VERSION_1_4);
      VL_CHECK(!use_vbo || (use_vbo && (GLEW_ARB_vertex_buffer_object||GLEW_VERSION_1_5||GLEW_VERSION_3_0)))
      use_vbo &= GLEW_ARB_vertex_buffer_object||GLEW_VERSION_1_5||GLEW_VERSION_3_0; // && indices()->gpuBuffer()->handle() && indices()->sizeGPU();
      if ( !use_vbo && !indices()->size() )
        return;

      // apply patch parameters if any and if using PT_PATCHES
      applyPatchParameters();

      // primitive restart enable
      if(primitiveRestartEnabled())
      {
        if(GLEW_VERSION_3_1)
        {
          glEnable(GL_PRIMITIVE_RESTART);
          glPrimitiveRestartIndex(primitiveRestartIndex());
        }
        else
        if(GLEW_NV_primitive_restart)
        {
          glEnable(GL_PRIMITIVE_RESTART_NV);
          glPrimitiveRestartIndexNV(primitiveRestartIndex());
        }
        else
        {
          vl::Log::error("MultiDrawElements error: primitive restart not supported by this OpenGL implementation!\n");
          VL_TRAP();
          return;
        }
      }

      GLvoid **indices_ptr = (GLvoid**)&mPointerVector[0];
      if (use_vbo && indices()->gpuBuffer()->handle())
      {
        VL_glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indices()->gpuBuffer()->handle());
        indices_ptr = (GLvoid**)&mNULLPointerVector[0];
      }
      else
        VL_glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

      if (baseVertices().size())
      {
        VL_CHECK( baseVertices().size() == pointerVector().size() )
        VL_CHECK( baseVertices().size() == countVector().size() )
        if (GLEW_ARB_draw_elements_base_vertex || GLEW_VERSION_3_1)
          glMultiDrawElementsBaseVertex( 
            primitiveType(), (GLsizei*)&mCountVector[0], indices()->glType(), indices_ptr, (GLsizei)mCountVector.size(), (GLint*)&mBaseVertices[0] 
          );
        else
        {
          vl::Log::error("MultiDrawElements::render(): glMultiDrawElementsBaseVertex() not supported!\n"
            "OpenGL 3.1 or GL_ARB_draw_elements_base_vertex extension required.\n"
          );
        }
      }
Beispiel #3
0
float CSSPrimitiveValue::getFloatValue(unsigned short unitType)
{
    if(!impl)
        return 0;
    // ### add unit conversion
    if(primitiveType() != unitType)
        throw CSSException(CSSException::SYNTAX_ERR);
    return ((CSSPrimitiveValueImpl *)impl)->floatValue(unitType);
}
double CSSPrimitiveValue::computeLengthDouble(RenderStyle* style, double multiplier, bool computingFontSize)
{
    unsigned short type = primitiveType();

    // We do not apply the zoom factor when we are computing the value of the font-size property.  The zooming
    // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference
    // as well as enforcing the implicit "smart minimum."  In addition the CSS property text-size-adjust is used to
    // prevent text from zooming at all.  Therefore we will not apply the zoom here if we are computing font-size.
    bool applyZoomMultiplier = !computingFontSize;

    double factor = 1.0;
    switch (type) {
        case CSS_EMS:
            applyZoomMultiplier = false;
            factor = computingFontSize ? style->fontDescription().specifiedSize() : style->fontDescription().computedSize();
            break;
        case CSS_EXS:
            // FIXME: We have a bug right now where the zoom will be applied twice to EX units.
            // We really need to compute EX using fontMetrics for the original specifiedSize and not use
            // our actual constructed rendering font.
            applyZoomMultiplier = false;
            factor = style->font().xHeight();
            break;
        case CSS_PX:
            break;
        case CSS_CM:
            factor = cssPixelsPerInch / 2.54; // (2.54 cm/in)
            break;
        case CSS_MM:
            factor = cssPixelsPerInch / 25.4;
            break;
        case CSS_IN:
            factor = cssPixelsPerInch;
            break;
        case CSS_PT:
            factor = cssPixelsPerInch / 72.0;
            break;
        case CSS_PC:
            // 1 pc == 12 pt
            factor = cssPixelsPerInch * 12.0 / 72.0;
            break;
        default:
            return -1.0;
    }

    double result = getDoubleValue() * factor;
    if (!applyZoomMultiplier || multiplier == 1.0)
        return result;
     
    // Any original result that was >= 1 should not be allowed to fall below 1.  This keeps border lines from
    // vanishing.
    double zoomedResult = result * multiplier;
    if (result >= 1.0)
        zoomedResult = max(1.0, zoomedResult);
    return zoomedResult;
}
void Renderable::render()
{
	switch (primitiveType()) {
	case kPrimitiveTypeTriangles:
		glDrawArrays(GL_TRIANGLES, 0, numVertices());
		break;

	default:
		break;
	}
}
float CSSPrimitiveValue::getFloatValue( unsigned short unitType )
{
    if(!impl) return 0;
    // ### add unit conversion
    if(primitiveType() != unitType)
#if KHTML_NO_EXCEPTIONS
	{ _exceptioncode = CSSException::SYNTAX_ERR; return 0; }
#else
	throw CSSException(CSSException::SYNTAX_ERR);
#endif
    return ((CSSPrimitiveValueImpl *)impl)->getFloatValue( unitType );
}
Beispiel #7
0
bool CSSPrimitiveValue::getDoubleValueInternal(UnitTypes requestedUnitType, double* result) const
{
    if (!isValidCSSUnitTypeForDoubleConversion(static_cast<UnitTypes>(m_primitiveUnitType)) || !isValidCSSUnitTypeForDoubleConversion(requestedUnitType))
        return false;

    UnitTypes sourceUnitType = static_cast<UnitTypes>(primitiveType());
    if (requestedUnitType == sourceUnitType || requestedUnitType == CSS_DIMENSION) {
        *result = getDoubleValue();
        return true;
    }

    UnitCategory sourceCategory = unitCategory(sourceUnitType);
    ASSERT(sourceCategory != UOther);

    UnitTypes targetUnitType = requestedUnitType;
    UnitCategory targetCategory = unitCategory(targetUnitType);
    ASSERT(targetCategory != UOther);

    // Cannot convert between unrelated unit categories if one of them is not UNumber.
    if (sourceCategory != targetCategory && sourceCategory != UNumber && targetCategory != UNumber)
        return false;

    if (targetCategory == UNumber) {
        // We interpret conversion to CSS_NUMBER as conversion to a canonical unit in this value's category.
        targetUnitType = canonicalUnitTypeForCategory(sourceCategory);
        if (targetUnitType == CSS_UNKNOWN)
            return false;
    }

    if (sourceUnitType == CSS_NUMBER) {
        // We interpret conversion from CSS_NUMBER in the same way as CSSParser::validUnit() while using non-strict mode.
        sourceUnitType = canonicalUnitTypeForCategory(targetCategory);
        if (sourceUnitType == CSS_UNKNOWN)
            return false;
    }

    double convertedValue = getDoubleValue();

    // First convert the value from m_primitiveUnitType to canonical type.
    double factor = conversionToCanonicalUnitsScaleFactor(sourceUnitType);
    convertedValue *= factor;

    // Now convert from canonical type to the target unitType.
    factor = conversionToCanonicalUnitsScaleFactor(targetUnitType);
    convertedValue /= factor;

    *result = convertedValue;
    return true;
}
Beispiel #8
0
static GConfValueType uniformType(const QList<QVariant> &list)
{
    GConfValueType result = GCONF_VALUE_INVALID;

    foreach (const QVariant &elt, list) {
        GConfValueType elt_type = primitiveType (elt);

        if (elt_type == GCONF_VALUE_INVALID)
            return GCONF_VALUE_INVALID;

        if (result == GCONF_VALUE_INVALID)
            result = elt_type;
        else if (result != elt_type)
            return GCONF_VALUE_INVALID;
    }
Beispiel #9
0
double CSSPrimitiveValue::computeLengthFloat(RenderStyle *style, bool applyZoomFactor)
{
    unsigned short type = primitiveType();

    // We always assume 96 CSS pixels in a CSS inch. This is the cold hard truth of the Web.
    // At high DPI, we may scale a CSS pixel, but the ratio of the CSS pixel to the so-called
    // "absolute" CSS length units like inch and pt is always fixed and never changes.
    double cssPixelsPerInch = 96.;

    double factor = 1.;
    switch(type) {
    case CSS_EMS:
        factor = applyZoomFactor ?
          style->fontDescription().computedSize() :
          style->fontDescription().specifiedSize();
        break;
    case CSS_EXS: {
        // FIXME: We have a bug right now where the zoom will be applied multiple times to EX units.
        // We really need to compute EX using fontMetrics for the original specifiedSize and not use
        // our actual constructed rendering font.
        factor = style->font().xHeight();
        break;
    }
    case CSS_PX:
        break;
    case CSS_CM:
        factor = cssPixelsPerInch/2.54; // (2.54 cm/in)
        break;
    case CSS_MM:
        factor = cssPixelsPerInch/25.4;
        break;
    case CSS_IN:
        factor = cssPixelsPerInch;
        break;
    case CSS_PT:
        factor = cssPixelsPerInch/72.;
        break;
    case CSS_PC:
        // 1 pc == 12 pt
        factor = cssPixelsPerInch*12./72.;
        break;
    default:
        return -1;
    }

    return getFloatValue() * factor;
}
Beispiel #10
0
vesShaderProgram::vesShaderProgram() : vesMaterialAttribute()
{
    this->m_internal = new vesInternal();

    this->m_type    = vesMaterialAttribute::Shader;
    this->m_binding = vesMaterialAttribute::BindAll;

    vesSharedPtr<vesEngineUniform> vertexHasColors (new vesHasVertexColors());
    vesSharedPtr<vesEngineUniform> primitiveType (new vesPrimitiveType());

    this->m_internal->m_engineUniforms.push_back(vertexHasColors);
    this->m_internal->m_engineUniforms.push_back(primitiveType);

    for (size_t i=0; i < this->m_internal->m_engineUniforms.size(); ++i) {
        this->addUniform(this->m_internal->m_engineUniforms[i]->uniform());
    }
}
Beispiel #11
0
void TexturedGeometry::setTextureRect(const QRectF &tr, int texIndex)
{
    setTexturePoint(0, tr.topLeft(), texIndex);
    setTexturePoint(1, tr.bottomLeft(), texIndex);
    switch (primitiveType()) {
    case TriangleStrip:
        setTexturePoint(2, tr.topRight(), texIndex);
        setTexturePoint(3, tr.bottomRight(), texIndex);
        break;
    case TriangleFan:
        setTexturePoint(3, tr.topRight(), texIndex);
        setTexturePoint(2, tr.bottomRight(), texIndex);
        break;
    case Triangles:
        break;
    default:
        break;
    }
}
Beispiel #12
0
void TexturedGeometry::setGeometryRect(const QRectF &r)
{
    setGeometryPoint(0, r.topLeft());
    setGeometryPoint(1, r.bottomLeft());
    switch (primitiveType()) {
    case TriangleStrip:
        setGeometryPoint(2, r.topRight());
        setGeometryPoint(3, r.bottomRight());
        break;
    case TriangleFan:
        setGeometryPoint(3, r.topRight());
        setGeometryPoint(2, r.bottomRight());
        break;
    case Triangles:
        break;
    default:
        break;
    }
}
Beispiel #13
0
bool
UIRenderer::render(const Ibl::RenderRequest* request,
                   const Ibl::GpuTechnique* technique) const
{
    if (_drawIndexed)
    {
        return _device->drawIndexedPrimitive(_currentVertexBuffer->vertexDeclaration(), 
                                             _indexBuffer,
                                             _currentVertexBuffer, technique, (PrimitiveType)primitiveType(),
                                             _primitiveCount, 0, _vertexOffset);

    }
    else
    {
        return _device->drawPrimitive(_currentVertexBuffer->vertexDeclaration(), _currentVertexBuffer, technique,
            (PrimitiveType)primitiveType(), _primitiveCount, _vertexOffset);
    }

    return true;
}
Beispiel #14
0
std::vector<ModelObj::Mesh>::iterator meshCommandAllocate(std::vector<ModelObj::Model>::iterator modelIter, std::vector<ModelObj::Mesh>::iterator meshIter, const std::string command, const std::string content, const int currentLine)
{
    //count elements in content
    const int count = countElements(content);
    //check what type the face has
    ModelObj::PrimitiveType foundType = primitiveType(command, content, currentLine);
    //compare to type of current mesh
    if (-1 >= meshIter->primitiveType) {
        //if the current mesh has a bad primitive type this means it is uninitialized. set it
        meshIter->primitiveType = foundType;
    }
    else if (foundType != meshIter->primitiveType || foundType == ModelObj::LINE_STRIP || foundType == ModelObj::POLYGON) {
        //the mesh already has a mesh type, but it isn't the same, start a new point mesh
        //if it is LINE_STRIP or POLYGON we need to start a new mesh anyway, 
        //because otherwise the line strips or polygons would be connected...
        ModelObj::Mesh newMesh;
        newMesh.primitiveType = foundType;
        modelIter->meshes.push_back(newMesh);
        meshIter = modelIter->meshes.begin() + modelIter->meshes.size() - 1;
    }
    meshIter->nrOfIndices += count;
    meshIter->nrOfPrimitives++;
    return meshIter;
}
Beispiel #15
0
std::vector<ModelObj::Mesh>::iterator meshCommandRead(std::vector<ModelObj::Model>::iterator modelIter, std::vector<ModelObj::Mesh>::iterator meshIter, const std::string command, const std::string content, const int currentLine)
{
    //count elements in content
    const int count = countElements(content);
    //check what type the face has
    ModelObj::PrimitiveType foundType = primitiveType(command, content, currentLine);
    //compare to type of current mesh
    if (foundType != meshIter->primitiveType || foundType == ModelObj::LINE_STRIP || foundType == ModelObj::POLYGON) {
        //the mesh already has a mesh type, but it isn't the same, switch to next mesh
        //if it is LINE_STRIP or POLYGON we need to switch to a new mesh anyway, 
        //because otherwise the line strips or polygons would be connected...
        meshIter++;
    }
    //read data from command
    //create stream object from string
    std::istringstream cstream(content);
    while (!cstream.eof()) {
        //retrieve first element
        std::string element;
        cstream >> element;
        //count how many parts (vertex/texcoord/normal) this has. all following elements have to have the same
        //no '/'   --> only vertex index
        //one '/'  --> vertex and texture index
        //one "//" --> vertex and normal index
        //two '/'  --> vertex, texture and normal index
        bool hasNormals = false;
        bool hasTextures = false;
        if (element.find("//") != std::string::npos) {
            hasNormals = true;
        }
        else if (element.find("/") != std::string::npos) {
            hasTextures = true;
            if (element.find("/") != element.rfind("/")) {
                hasNormals = true;
            }
        }
        //now we can allocate the index array as now we know which elements actually exist
        bool wasAllocation = false;
        if (NULL == meshIter->vertexIndices) {
            meshIter->vertexIndices = new int[meshIter->nrOfIndices];
            wasAllocation = true;
        }
        if (hasNormals) {
            if (NULL == meshIter->normalIndices) {
                meshIter->normalIndices = new int[meshIter->nrOfIndices];
                wasAllocation = true;
            }
        }
        if (hasTextures) {
            if (NULL == meshIter->textureIndices) {
                meshIter->textureIndices = new int[meshIter->nrOfIndices];
                wasAllocation = true;
            }
        }
        if (wasAllocation) {
            //this is the first element of the mesh, clear counters
            meshIter->nrOfIndices = 0;
            meshIter->nrOfPrimitives = 0;
        }
        //now get elements from stream
        cstream.clear();
        cstream.seekg(0, std::ios::beg);
        while (!cstream.eof()) {
            int value = 0;
            cstream >> element;
            std::istringstream estream(element);
            //get vertex index
            estream >> value;
            meshIter->vertexIndices[meshIter->nrOfIndices] = value - 1;
            //if this has a texture coordinate read it
            if (hasTextures) {
                //discard '/'
                estream.ignore(1, '/');
                //read texture coord
                estream >> value;
                meshIter->textureIndices[meshIter->nrOfIndices] = value - 1;
                if (hasNormals) {
                    //discard '/'
                    estream.ignore(1, '/');
                    //read normal
                    estream >> value;
                    meshIter->normalIndices[meshIter->nrOfIndices] = value - 1;
                }
            }
            else {
                if (hasNormals) {
                    //discard '//'
                    estream.ignore(1, '/');
                    estream.ignore(1, '/');
                    //read normal
                    estream >> value;
                    meshIter->normalIndices[meshIter->nrOfIndices] = value - 1;
                }
            }
            meshIter->nrOfIndices++;
        }
    }
Beispiel #16
0
void GlobFit::dumpData(const std::vector<RelationEdge>& vecRelationEdge, const std::string& stageName)
{
  size_t maxVerticesNum = 0;
  for (size_t i = 0, iEnd = _vecPrimitive.size(); i < iEnd; ++ i) {
    Primitive* pPrimitive = _vecPrimitive[i];
    pPrimitive->prepareParameters();
    maxVerticesNum = std::max(pPrimitive->getPointIdx().size(), maxVerticesNum);
  }

  std::locale loc("C");

  std::string path = boost::filesystem::current_path().string();
  path = path+"/matlab/data/"+stageName+"/";
  boost::filesystem::create_directories(path);
  std::ofstream constraints((path+"constraints.dat").c_str());
  std::ofstream primitiveType((path+"primitiveType.dat").c_str());
  std::ofstream inputParameters((path+"inputParameters.dat").c_str());
  std::ofstream numVertices((path+"numVertices.dat").c_str());
  std::ofstream coordX((path+"coordX.dat").c_str());
  std::ofstream coordY((path+"coordY.dat").c_str());
  std::ofstream coordZ((path+"coordZ.dat").c_str());
  std::ofstream normalX((path+"normalX.dat").c_str());
  std::ofstream normalY((path+"normalY.dat").c_str());
  std::ofstream normalZ((path+"normalZ.dat").c_str());
  std::ofstream confVertices((path+"confVertices.dat").c_str());

  constraints.imbue(loc);
  primitiveType.imbue(loc);
  inputParameters.imbue(loc);
  inputParameters.precision(16);
  numVertices.imbue(loc);
  coordX.imbue(loc);
  coordX.precision(16);
  coordY.imbue(loc);
  coordY.precision(16);
  coordZ.imbue(loc);
  coordZ.precision(16);
  normalX.imbue(loc);
  normalX.precision(16);
  normalY.imbue(loc);
  normalY.precision(16);
  normalZ.imbue(loc);
  normalZ.precision(16);
  confVertices.imbue(loc);
  confVertices.precision(16);

  for (size_t i = 0, iEnd = vecRelationEdge.size(); i < iEnd; ++ i) {
    const RelationEdge& relationEdge = vecRelationEdge[i];
    constraints << relationEdge << std::endl;
  }

  for (size_t i = 0, iEnd = _vecPrimitive.size(); i < iEnd; ++ i) {
    Primitive* pPrimitive = _vecPrimitive[i];

    primitiveType << pPrimitive->getType() << std::endl;

    pPrimitive->prepareParameters();
    for (size_t j = 0, jEnd = Primitive::getNumParameter(); j < jEnd; ++ j) {
      inputParameters << pPrimitive->getParameter(j) << " ";
    }
    inputParameters << std::endl;

    numVertices << pPrimitive->getPointIdx().size() << std::endl;
    for (size_t j = 0, jEnd = pPrimitive->getPointIdx().size(); j < jEnd; ++ j) {
      const RichPoint* richPoint = _vecPointSet[pPrimitive->getPointIdx()[j]];
      const Point& point = richPoint->point;
      const Vector& normal = richPoint->normal;
      coordX << point.x() << " ";
      coordY << point.y() << " ";
      coordZ << point.z() << " ";
      normalX << normal.x() << " ";
      normalY << normal.y() << " ";
      normalZ << normal.z() << " ";
      confVertices << richPoint->confidence << " ";
    }

    for (size_t j = pPrimitive->getPointIdx().size(); j < maxVerticesNum; ++ j) {
      coordX << 0 << " ";
      coordY << 0 << " ";
      coordZ << 0 << " ";
      normalX << 0 << " ";
      normalY << 0 << " ";
      normalZ << 0 << " ";
      confVertices << 0 << " ";
    }
    coordX << std::endl;
    coordY << std::endl;
    coordZ << std::endl;
    normalX << std::endl;
    normalY << std::endl;
    normalZ << std::endl;
    confVertices << std::endl;
  }

  return;
}
Beispiel #17
0
double CSSPrimitiveValue::computeLengthDouble(const CSSToLengthConversionData& conversionData) const
{
    if (m_primitiveUnitType == CSS_CALC)
        // The multiplier and factor is applied to each value in the calc expression individually
        return m_value.calc->computeLengthPx(conversionData);

    double factor;

    switch (primitiveType()) {
    case CSS_EMS:
        ASSERT(conversionData.style());
        factor = conversionData.computingFontSize() ? conversionData.style()->fontDescription().specifiedSize() : conversionData.style()->fontDescription().computedSize();
        break;
    case CSS_EXS:
        ASSERT(conversionData.style());
        // FIXME: We have a bug right now where the zoom will be applied twice to EX units.
        // We really need to compute EX using fontMetrics for the original specifiedSize and not use
        // our actual constructed rendering font.
        if (conversionData.style()->fontMetrics().hasXHeight())
            factor = conversionData.style()->fontMetrics().xHeight();
        else
            factor = (conversionData.computingFontSize() ? conversionData.style()->fontDescription().specifiedSize() : conversionData.style()->fontDescription().computedSize()) / 2.0;
        break;
    case CSS_REMS:
        if (conversionData.rootStyle())
            factor = conversionData.computingFontSize() ? conversionData.rootStyle()->fontDescription().specifiedSize() : conversionData.rootStyle()->fontDescription().computedSize();
        else
            factor = 1.0;
        break;
    case CSS_CHS:
        ASSERT(conversionData.style());
        factor = conversionData.style()->fontMetrics().zeroWidth();
        break;
    case CSS_PX:
        factor = 1.0;
        break;
    case CSS_CM:
        factor = cssPixelsPerInch / 2.54; // (2.54 cm/in)
        break;
    case CSS_MM:
        factor = cssPixelsPerInch / 25.4;
        break;
    case CSS_IN:
        factor = cssPixelsPerInch;
        break;
    case CSS_PT:
        factor = cssPixelsPerInch / 72.0;
        break;
    case CSS_PC:
        // 1 pc == 12 pt
        factor = cssPixelsPerInch * 12.0 / 72.0;
        break;
    case CSS_CALC_PERCENTAGE_WITH_LENGTH:
    case CSS_CALC_PERCENTAGE_WITH_NUMBER:
        ASSERT_NOT_REACHED();
        return -1.0;
    case CSS_VH:
        factor = conversionData.viewportHeightFactor();
        break;
    case CSS_VW:
        factor = conversionData.viewportWidthFactor();
        break;
    case CSS_VMAX:
        factor = conversionData.viewportMaxFactor();
        break;
    case CSS_VMIN:
        factor = conversionData.viewportMinFactor();
        break;
    default:
        ASSERT_NOT_REACHED();
        return -1.0;
    }

    // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming
    // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference
    // as well as enforcing the implicit "smart minimum."
    double result = getDoubleValue() * factor;
    if (conversionData.computingFontSize() || isFontRelativeLength())
        return result;

    return result * conversionData.zoom();
}