void SymbolBucket::addFeatures(uintptr_t tileUID, SpriteAtlas& spriteAtlas, GlyphAtlas& glyphAtlas, GlyphStore& glyphStore) { float horizontalAlign = 0.5; float verticalAlign = 0.5; switch (layout.text.anchor) { case TextAnchorType::Top: case TextAnchorType::Bottom: case TextAnchorType::Center: break; case TextAnchorType::Right: case TextAnchorType::TopRight: case TextAnchorType::BottomRight: horizontalAlign = 1; break; case TextAnchorType::Left: case TextAnchorType::TopLeft: case TextAnchorType::BottomLeft: horizontalAlign = 0; break; } switch (layout.text.anchor) { case TextAnchorType::Left: case TextAnchorType::Right: case TextAnchorType::Center: break; case TextAnchorType::Bottom: case TextAnchorType::BottomLeft: case TextAnchorType::BottomRight: verticalAlign = 1; break; case TextAnchorType::Top: case TextAnchorType::TopLeft: case TextAnchorType::TopRight: verticalAlign = 0; break; } const float justify = layout.text.justify == TextJustifyType::Right ? 1 : layout.text.justify == TextJustifyType::Left ? 0 : 0.5; auto fontStack = glyphStore.getFontStack(layout.text.font); for (const auto& feature : features) { if (feature.geometry.empty()) continue; Shaping shapedText; PositionedIcon shapedIcon; GlyphPositions face; // if feature has text, shape the text if (feature.label.length()) { shapedText = fontStack->getShaping( /* string */ feature.label, /* maxWidth: ems */ layout.placement != PlacementType::Line ? layout.text.maxWidth * 24 : 0, /* lineHeight: ems */ layout.text.lineHeight * 24, /* horizontalAlign */ horizontalAlign, /* verticalAlign */ verticalAlign, /* justify */ justify, /* spacing: ems */ layout.text.letterSpacing * 24, /* translate */ vec2<float>(layout.text.offset.value[0], layout.text.offset.value[1])); // Add the glyphs we need for this label to the glyph atlas. if (shapedText) { glyphAtlas.addGlyphs(tileUID, feature.label, layout.text.font, **fontStack, face); } } // if feature has icon, get sprite atlas position if (feature.sprite.length()) { auto image = spriteAtlas.getImage(feature.sprite, false); if (image) { shapedIcon = shapeIcon(*image, layout); assert((*image).spriteImage); if ((*image).spriteImage->sdf) { sdfIcons = true; } if ((*image).relativePixelRatio != 1.0f) { iconsNeedLinear = true; } } } // if either shapedText or icon position is present, add the feature if (shapedText || shapedIcon) { addFeature(feature.geometry, shapedText, shapedIcon, face); } } features.clear(); }
void SymbolLayout::prepare(const GlyphMap& glyphMap, const GlyphPositions& glyphPositions, const ImageMap& imageMap, const ImagePositions& imagePositions, const OverscaledTileID& tileID, const std::string& sourceID) { const bool textAlongLine = layout.get<TextRotationAlignment>() == AlignmentType::Map && layout.get<SymbolPlacement>() == SymbolPlacementType::Line; auto glyphMapIt = glyphMap.find(layout.get<TextFont>()); const Glyphs& glyphs = glyphMapIt != glyphMap.end() ? glyphMapIt->second : Glyphs(); auto glyphPositionsIt = glyphPositions.find(layout.get<TextFont>()); const GlyphPositionMap& glyphPositionMap = glyphPositionsIt != glyphPositions.end() ? glyphPositionsIt->second : GlyphPositionMap(); for (auto it = features.begin(); it != features.end(); ++it) { auto& feature = *it; if (feature.geometry.empty()) continue; std::pair<Shaping, Shaping> shapedTextOrientations; optional<PositionedIcon> shapedIcon; // if feature has text, shape the text if (feature.text) { auto applyShaping = [&] (const std::u16string& text, WritingModeType writingMode) { const float oneEm = 24.0f; const Shaping result = getShaping( /* string */ text, /* maxWidth: ems */ layout.get<SymbolPlacement>() != SymbolPlacementType::Line ? layout.evaluate<TextMaxWidth>(zoom, feature) * oneEm : 0, /* lineHeight: ems */ layout.get<TextLineHeight>() * oneEm, /* anchor */ layout.evaluate<TextAnchor>(zoom, feature), /* justify */ layout.evaluate<TextJustify>(zoom, feature), /* spacing: ems */ util::i18n::allowsLetterSpacing(*feature.text) ? layout.evaluate<TextLetterSpacing>(zoom, feature) * oneEm : 0.0f, /* translate */ Point<float>(layout.evaluate<TextOffset>(zoom, feature)[0] * oneEm, layout.evaluate<TextOffset>(zoom, feature)[1] * oneEm), /* verticalHeight */ oneEm, /* writingMode */ writingMode, /* bidirectional algorithm object */ bidi, /* glyphs */ glyphs); return result; }; shapedTextOrientations.first = applyShaping(*feature.text, WritingModeType::Horizontal); if (util::i18n::allowsVerticalWritingMode(*feature.text) && textAlongLine) { shapedTextOrientations.second = applyShaping(util::i18n::verticalizePunctuation(*feature.text), WritingModeType::Vertical); } } // if feature has icon, get sprite atlas position if (feature.icon) { auto image = imageMap.find(*feature.icon); if (image != imageMap.end()) { shapedIcon = PositionedIcon::shapeIcon( imagePositions.at(*feature.icon), layout.evaluate<IconOffset>(zoom, feature), layout.evaluate<IconAnchor>(zoom, feature), layout.evaluate<IconRotate>(zoom, feature) * util::DEG2RAD); if (image->second->sdf) { sdfIcons = true; } if (image->second->pixelRatio != pixelRatio) { iconsNeedLinear = true; } else if (layout.get<IconRotate>().constantOr(1) != 0) { iconsNeedLinear = true; } } } // if either shapedText or icon position is present, add the feature if (shapedTextOrientations.first || shapedIcon) { addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon, glyphPositionMap, tileID, sourceID); } feature.geometry.clear(); } compareText.clear(); }