Apple Xsan_2_Admin_Guide_v2.3.pdf Manuel Apple sur Fnac.com - Pour voir la liste complète des manuels APPLE, cliquez ici

 

 

TELECHARGER LE PDF sur :

http://movies.apple.com/media/us/osx/2012/server/docs/Xsan_2_Admin_Guide_v2.3.pdf

Commander un produit Apple sur Fnac.com

 

 

Voir également d'autres Guides APPLE :

Apple-macbook_pro-retina-mid-2012-important_product_info_f.pdf-manuel

Apple-iOS_Security_May12.pdf-manue

Apple-Mac-Pro-2008-Performance-and-Productivity-for-Creative-Pros

Apple-iPod_shuffle_4thgen_Manuale_utente.pdf-Italie-Manuel

Apple-KernelProgramming.pdf-manuel

Apple-Core-Data-Model-Versioning-and-Data-Migration-Programming-Guide-manuel

Apple-RED_Workflows_with_Final_Cut_Pro_X.pdf-manuel

Apple-Transitioning-to-ARC-Release-Notes-manuel

Apple-iTunes-Connect-Sales-and-Trends-Guide-manuel

Apple-App-Sandbox-Design-Guide-manuel

Apple-String-Programming-Guide-manuel

Apple-Secure-Coding-Guide-manuel

Apple_AirPort_Networks_Early2009.pdf-manuel

Apple-TimeCapsule_SetupGuide_TA.pdf-manuel

Apple-time_capsule_4th_gen_setup.pdf-manuel

Apple-TimeCapsule_SetupGuide.pdf-manuel

Apple-TimeCapsule_SetupGuide_CH.pdf-Chinois-manuel

Apple-CodeSigningGuide.pdf-manuel

Apple-ViewControllerPGforiOS.pdf-manuel

Apple-KeyValueObserving.pdf-manuel

Apple-mac_mini-late-2012-quick_start.pdf-manuel

Apple-OS-X-Mountain-Lion-Core-Technologies-Overview-June-2012-manuel

Apple-OS-X-Server-Product-Overview-June-2012-manuel

Apple-Apple_Server_Diagnostics_UG_109.pdf-manuel

Apple-PackageMaker_UserGuide.pdf-manuel

Apple-Instrumentos_y_efectos_de_Logic_Studio.pdf-Manuel

Apple-ipod_nano_kayttoopas.pdf-Finlande-Manuel

Apple_ProRes_White_Paper_October_2012.pdf-Manuel

Apple-wp_osx_configuration_profiles.pdf-Manuel

Apple-UsingiTunesProducerFreeBooks.pdf-Manuel

Apple-ipad_manual_do_usuario.pdf-Portugais-Manuel

Apple-Instruments_et_effets_Logic_Studio.pdf-Manuel

Apple-ipod_touch_gebruikershandleiding.pdf-Neerlandais-Manuel

AppleiPod_shuffle_4thgen_Manual_del_usuario.pdf-Espagnol-Manuel

Apple-Premiers-contacts-avec-votre-PowerBook-G4-Manuel

Apple_Composite_AV_Cable.pdf-Manuel

Apple-iPod_shuffle_3rdGen_UG_DK.pdf-Danemark-Manuel

Apple-iPod_classic_160GB_Benutzerhandbuch.pdf-Allemand-Manuel

Apple-VoiceOver_GettingStarted-Manuel

Apple-iPod_touch_2.2_Benutzerhandbuch.pdf-Allemand-Manuel

Apple-Apple_TV_Opstillingsvejledning.pdf-Allemand-Manuel

Apple-iPod_shuffle_4thgen_Manuale_utente.pdf-Italie-Manuel

Apple-iphone_prirucka_uzivatela.pdf-Manuel

Apple-Aan-de-slag-Neerlandais-Manuel

Apple-airmac_express-80211n-2nd-gen_setup_guide.pdf-Thailande-Manuel

Apple-ipod_nano_benutzerhandbuch.pdf-Allemand-Manuel

Apple-aperture3.4_101.pdf-Manuel

Apple-Pages09_Anvandarhandbok.pdf-Manuel

Apple-nike_plus_ipod_sensor_ug_la.pdf-Mexique-Manuel

Apple-ResEdit-Reference-For-ResEdit02.1-Manuel

Apple-ipad_guide_de_l_utilisateur.pdf-Manuel

Apple-Compressor-4-Benutzerhandbuch-Allemand-Manuel

Apple-AirPort_Networks_Early2009_DK.pdf-Danemark-Manuel

Apple-MacBook_Pro_Mid2007_2.4_2.2GHz_F.pdf-Manuel

Apple-MacBook_13inch_Mid2010_UG_F.pdf-Manuel

Apple-Xserve-RAID-Presentation-technologique-Janvier-2004-Manuel

Apple-MacBook_Pro_15inch_Mid2010_F.pdf-Manuel

Apple-AirPort_Express-opstillingsvejledning.pdf-Danemark-Manuel

Apple-DEiPod_photo_Benutzerhandbuch_DE0190269.pdf-Allemand-Manuel

Apple-Final-Cut-Pro-X-Logic-Effects-Reference-Manuel

Apple-iPod_touch_2.1_Brugerhandbog.pdf-Danemark-Manuel

Apple-Remote-Desktop-Administratorhandbuch-Version-3.1-Allemand-Manuel

Apple-Qmaster-4-User-Manual-Manuel

Apple-Server_Administration_v10.5.pdf-Manuel

Apple-ipod_classic_features_guide.pdf-Manuel

Apple-Lecteur-Optique-Manuel

Apple-Carte-AirPort-Manuel

Apple-iPhone_Finger_Tips_Guide.pdf-Anglais-Manuel

Apple-Couvercle-Manuel

Apple-battery.cube.pdf-Manuel

Apple-Boitier-de-l-ordinateur-Manuel

Apple-Pile-Interne-Manuel

Apple-atacable.pdf-Manuel

Apple-videocard.pdf-Manuel

Apple-Guide_de_configuration_de_l_Airport_Express_5.1.pdf-Manuel

Apple-iMac_Mid2010_UG_F.pdf-Manuel

Apple-MacBook_13inch_Mid2009_F.pdf-Manuel

Apple-MacBook_Mid2007_UserGuide.F.pdf-Manuel

Apple-Designing_AirPort_Networks_10.5-Windows_F.pdf-Manuel

Apple-Administration_de_QuickTime_Streaming_et_Broadcasting_10.5.pdf-Manuel

Apple-Opstillingsvejledning_til_TimeCapsule.pdf-Danemark-Manuel

Apple-iPod_nano_5th_gen_Benutzerhandbuch.pdf-Manuel

Apple-iOS_Business.pdf-Manuel

Apple-AirPort_Extreme_Installationshandbuch.pdf-Manuel

Apple-Final_Cut_Express_4_Installation_de_votre_logiciel.pdf-Manuel

Apple-MacBook_Pro_15inch_2.53GHz_Mid2009.pdf-Manuel

Apple-Network_Services.pdf-Manuel

Apple-Aperture_Performing_Adjustments_f.pdf-Manuel

Apple-Supplement_au_guide_Premiers_contacts.pdf-Manuel

Apple-Administration_des_images_systeme_et_de_la_mise_a_jour_de_logiciels_10.5.pdf-Manuel

Apple-Mac_OSX_Server_v10.6_Premiers_contacts.pdf-Francais-Manuel

Apple-Designing_AirPort_Networks_10.5-Windows_F.pdf-Manuel

Apple-Mise_a_niveau_et_migration_v10.5.pdf-Manue

Apple-MacBookPro_Late_2007_2.4_2.2GHz_F.pdf-Manuel

Apple-Mac_mini_Late2009_SL_Server_F.pdf-Manuel

Apple-Mac_OS_X_Server_10.5_Premiers_contacts.pdf-Manuel

Apple-iPod_touch_2.0_Guide_de_l_utilisateur_CA.pdf-Manuel

Apple-MacBook_Pro_17inch_Mid2010_F.pdf-Manuel

Apple-Comment_demarrer_Leopard.pdf-Manuel

Apple-iPod_2ndGen_USB_Power_Adapter-FR.pdf-Manuel

Apple-Feuille_de_operations_10.4.pdf-Manuel

Apple-Time_Capsule_Installationshandbuch.pdf-Allemand-Manuel

Apple-F034-2262AXerve-grappe.pdf-Manuel

Apple-Mac_Pro_Early2009_4707_UG_F

Apple-imacg5_17inch_Power_Supply

Apple-Logic_Studio_Installieren_Ihrer_Software_Retail

Apple-IntroductionXserve1.0.1

Apple-Aperture_Getting_Started_d.pdf-Allemand

Apple-getting_started_with_passbook

Apple-iPod_mini_2nd_Gen_UserGuide.pdf-Anglais

Apple-Deploiement-d-iPhone-et-d-iPad-Reseaux-prives-virtuels

Apple-F034-2262AXerve-grappe

Apple-Mac_OS_X_Server_Glossaire_10.5

Apple-FRLogic_Pro_7_Guide_TDM

Apple-iphone_bluetooth_headset_userguide

Apple-Administration_des_services_reseau_10.5

Apple-imacg5_17inch_harddrive

Apple-iPod_nano_4th_gen_Manuale_utente

Apple-iBook-G4-Getting-Started

Apple-XsanGettingStarted

Apple-Mac_mini_UG-Early2006

Apple-Guide_des_fonctionnalites_de_l_iPod_classic

Apple-Guide_de_configuration_d_Xsan_2

Apple-MacBook_Late2006_UsersGuide

Apple-sur-Fnac.com

Apple-Mac_mini_Mid2010_User_Guide_F.pdf-Francais

Apple-PowerBookG3UserManual.PDF.Anglais

Apple-Installation_de_votre_logiciel_Logic_Studio_Retail

Apple-Pages-Guide-de-l-utilisateur

Apple-MacBook_Pro_13inch_Mid2009.pdf.Anglais

Apple-MacBook_Pro_15inch_Mid2009

Apple-Installation_de_votre_logiciel_Logic_Studio_Upgrade

Apple-FRLogic_Pro_7_Guide_TDM

Apple-airportextreme_802.11n_userguide

Apple-iPod_shuffle_3rdGen_UG

Apple-iPod_classic_160GB_User_Guide

Apple-iPod_nano_5th_gen_UserGuide

Apple-ipod_touch_features_guide

Apple-Wireless_Mighty_Mouse_UG

Apple-Advanced-Memory-Management-Programming-Guide

Apple-iOS-App-Programming-Guide

Apple-Concurrency-Programming-Guide

Apple-MainStage-2-User-Manual-Anglais

Apple-iMacG3_2002MultilingualUserGuide

Apple-iBookG3_DualUSBUserGuideMultilingual.PDF.Anglais

Apple-imacG5_20inch_AirPort

Apple-Guide_de_l_utilisateur_de_Mac_Pro_Early_2008

Apple-Installation_de_votre_logiciel_Logic_Express_8

Apple-iMac_Guide_de_l_utilisateur_Mid2007

Apple-imacg5_20inch_OpticalDrive

Apple-FCP6_Formats_de_diffusion_et_formats_HD

Apple-prise_en_charge_des_surfaces_de_controle_logic_pro_8

Apple-Aperture_Quick_Reference_f

Apple-Shake_4_User_Manual

Apple-aluminumAppleKeyboard_wireless2007_UserGuide

Apple-ipod_shuffle_features_guide

Apple-Color-User-Manual

Apple-XsanGettingStarted

Apple-Migration_10.4_2e_Ed

Apple-MacBook_Air_SuperDrive

Apple-MacBook_Late2007-f

ApplePowerMacG5_(Early_2005)_UserGuide

Apple-iSightUserGuide

Apple-MacBook_Pro_Early_2008_Guide_de_l_utilisateur

Apple-Nouvelles-fonctionnalites-aperture-1.5

Apple-premiers_contacts_2e_ed_10.4.pdf-Mac-OS-X-Server

Apple-premiers_contacts_2e_ed_10.4

Apple-eMac_2005UserGuide

Apple-imacg5_20inch_Inverter

Apple-Keynote2_UserGuide.pdf-Japon

Apple-Welcome_to_Tiger.pdf-Japon

Apple-XsanAdminGuide_j.pdf-Japon

Apple-PowerBookG4_UG_15GE.PDF-Japon

Apple-Xsan_Migration.pdf-Japon

Apple-Xserve_Intel_DIY_TopCover_JA.pdf-Japon

Apple-iPod_nano_6thgen_User_Guide_J.pdf-Japon

Apple-Aperture_Photography_Fundamentals.pdf-Japon

Apple-nikeipod_users_guide.pdf-Japon

Apple-QuickTime71_UsersGuide.pdf-Japon

Apple-iMacG5_iSight_UG.pdf-Japon

Apple-Aperture_Performing_Adjustments_j.pdf-Japon

Apple-iMacG5_17inch_HardDrive.pdf-Japon

Apple-iPod_shuffle_Features_Guide_J.pdf-Japon

Apple-MacBook_Air_User_Guide.pdf-Japon

Apple-MacBook_UsersGuide.pdf-Japon

Apple-iPad_iOS4_Brukerhandbok.pdf-Norge-Norvege

Apple-Apple_AirPort_Networks_Early2009_H.pd-Norge-Norvege

Apple-iPod_classic_120GB_no.pdf-Norge-Norvege

Apple-StoreKitGuide.pdf-Japon

Apple-Xserve_Intel_DIY_ExpansionCardRiser_JA.pdf-Japon

Apple-iMacG5_Battery.pdf-Japon

Apple-Logic_Pro_8_Getting_Started.pdf-Japon

Apple-PowerBook-handbok-Norge-Norveg

Apple-iWork09_formler_og_funksjoner.pdf-Norge-Norvege

Apple-MacBook_Pro_15inch_Mid2010_H.pdf-Norge-Norvege

Apple-MacPro_HardDrive_DIY.pdf-Japon

Apple-iPod_Fifth_Gen_Funksjonsoversikt.pdf-Norge-Norvege

Apple-MacBook_13inch_white_Early2009_H.pdf-Norge-Norvege

Apple-GarageBand_09_Komme_i_gang.pdf-Norge-Norvege

Apple-MacBook_Pro_15inch_Mid2009_H.pdf-Norge-Norvege

Apple-imac_mid2011_ug_h.pdf-Norge-Norvege

Apple-iDVD_08_Komme_i_gang.pdf-Norge-Norvege

Apple-MacBook_Air_11inch_Late2010_UG_H.pdf-Norge-Norvege

Apple-iMac_Mid2010_UG_H.pdf-Norge-Norvege

Apple-MacBook_13inch_Mid2009_H.pdf-Norge-Norvege

/Apple-iPhone_3G_Viktig_produktinformasjon_H-Norge-Norvege

Apple-MacBook_13inch_Mid2010_UG_H.pdf-Norge-Norvege

Apple-macbook_air_13inch_mid2011_ug_no.pdf-Norge-Norvege

Apple-Mac_mini_Early2009_UG_H.pdf-Norge-Norvege

Apple-ipad2_brukerhandbok.pdf-Norge-Norvege

Apple-iPhoto_08_Komme_i_gang.pdf-Norge-Norvege

Apple-MacBook_Air_Brukerhandbok_Late2008.pdf-Norge-Norvege

Apple-Pages09_Brukerhandbok.pdf-Norge-Norvege

Apple-MacBook_13inch_Late2009_UG_H.pdf-Norge-Norvege

Apple-iPhone_3GS_Viktig_produktinformasjon.pdf-Norge-Norvege

Apple-MacBook_13inch_Aluminum_Late2008_H.pdf-Norge-Norvege

Apple-Wireless_Keyboard_Aluminum_2007_H-Norge-Norvege

Apple-NiPod_photo_Brukerhandbok_N0190269.pdf-Norge-Norvege

Apple-MacBook_Pro_13inch_Mid2010_H.pdf-Norge-Norvege

Apple-MacBook_Pro_17inch_Mid2010_H.pdf-Norge-Norvege

Apple-Velkommen_til_Snow_Leopard.pdf-Norge-Norvege.htm

Apple-TimeCapsule_Klargjoringsoversikt.pdf-Norge-Norvege

Apple-iPhone_3GS_Hurtigstart.pdf-Norge-Norvege

Apple-Snow_Leopard_Installeringsinstruksjoner.pdf-Norge-Norvege

Apple-iMacG5_iSight_UG.pdf-Norge-Norvege

Apple-iPod_Handbok_S0342141.pdf-Norge-Norvege

Apple-ipad_brukerhandbok.pdf-Norge-Norvege

Apple-GE_Money_Bank_Handlekonto.pdf-Norge-Norvege

Apple-MacBook_Air_11inch_Late2010_UG_H.pdf-Norge-Norvege

Apple-iPod_nano_6thgen_Brukerhandbok.pdf-Norge-Norvege

Apple-iPod_touch_iOS4_Brukerhandbok.pdf-Norge-Norvege

Apple-MacBook_Air_13inch_Late2010_UG_H.pdf-Norge-Norvege

Apple-MacBook_Pro_15inch_Early2011_H.pdf-Norge-Norvege

Apple-Numbers09_Brukerhandbok.pdf-Norge-Norvege

Apple-Welcome_to_Leopard.pdf-Japon

Apple-PowerMacG5_UserGuide.pdf-Norge-Norvege

Apple-iPod_touch_2.1_Brukerhandbok.pdf-Norge-Norvege

Apple-Boot_Camp_Installering-klargjoring.pdf-Norge-Norvege

Apple-MacOSX10.3_Welcome.pdf-Norge-Norvege

Apple-iPod_shuffle_3rdGen_UG_H.pdf-Norge-Norvege

Apple-iPhone_4_Viktig_produktinformasjon.pdf-Norge-Norvege

Apple_TV_Klargjoringsoversikt.pdf-Norge-Norvege

Apple-iMovie_08_Komme_i_gang.pdf-Norge-Norvege

Apple-iPod_classic_160GB_Brukerhandbok.pdf-Norge-Norvege

Apple-Boot_Camp_Installering_10.6.pdf-Norge-Norvege

Apple-Network-Services-Location-Manager-Veiledning-for-nettverksadministratorer-Norge-Norvege

Apple-iOS_Business_Mar12_FR.pdf

Apple-PCIDualAttachedFDDICard.pdf

Apple-Aperture_Installing_Your_Software_f.pdf

Apple-User_Management_Admin_v10.4.pdf

Apple-Compressor-4-ユーザーズマニュアル Japon

Apple-Network_Services_v10.4.pdf

Apple-iPod_2ndGen_USB_Power_Adapter-DE

Apple-Mail_Service_v10.4.pdf

Apple-AirPort_Express_Opstillingsvejledning_5.1.pdf

Apple-MagSafe_Airline_Adapter.pdf

Apple-L-Apple-Multiple-Scan-20-Display

Apple-Administration_du_service_de_messagerie_10.5.pdf

Apple-System_Image_Admin.pdf

Apple-iMac_Intel-based_Late2006.pdf-Japon

Apple-iPhone_3GS_Finger_Tips_J.pdf-Japon

Apple-Power-Mac-G4-Mirrored-Drive-Doors-Japon

Apple-AirMac-カード取り付け手順-Japon

Apple-iPhone開発ガイド-Japon

Apple-atadrive_pmg4mdd.j.pdf-Japon

Apple-iPod_touch_2.2_User_Guide_J.pdf-Japon

Apple-Mac_OS_X_Server_v10.2.pdf

Apple-AppleCare_Protection_Plan_for_Apple_TV.pdf

Apple_Component_AV_Cable.pdf

Apple-DVD_Studio_Pro_4_Installation_de_votre_logiciel

Apple-Windows_Services

Apple-Motion_3_New_Features_F

Apple-g4mdd-fw800-lowerfan

Apple-MacOSX10.3_Welcome

Apple-Print_Service

Apple-Xserve_Setup_Guide_F

Apple-PowerBookG4_17inch1.67GHzUG

Apple-iMac_Intel-based_Late2006

Apple-Installation_de_votre_logiciel

Apple-guide_des_fonctions_de_l_iPod_nano

Apple-Administration_de_serveur_v10.5

Apple-Mac-OS-X-Server-Premiers-contacts-Pour-la-version-10.3-ou-ulterieure

Apple-boot_camp_install-setup

Apple-iBookG3_14inchUserGuideMultilingual

Apple-mac_pro_server_mid2010_ug_f

Apple-Motion_Supplemental_Documentation

Apple-imac_mid2011_ug_f

Apple-iphone_guide_de_l_utilisateur

Apple-macbook_air_11inch_mid2011_ug_fr

Apple-NouvellesfonctionnalitesdeLogicExpress7.2

Apple-QT_Streaming_Server

Apple-Web_Technologies_Admin

Apple-Mac_Pro_Early2009_4707_UG

Apple-guide_de_l_utilisateur_de_Numbers08

Apple-Decouverte_d_Aperture_2

Apple-Guide_de_configuration_et_d'administration

Apple-mac_integration_basics_fr_106.

Apple-iPod_shuffle_4thgen_Guide_de_l_utilisateur

Apple-ARA_Japan

Apple-081811_APP_iPhone_Japanese_v5.4.pdf-Japan

Apple-Recycle_Contract120919.pdf-Japan

Apple-World_Travel_Adapter_Kit_UG

Apple-iPod_nano_6thgen_User_Guide

Apple-RemoteSupportJP

Apple-Mac_mini_Early2009_UG_F.pdf-Manuel-de-l-utilisateur

Apple-Compressor_3_Batch_Monitor_User_Manual_F.pdf-Manuel-de-l-utilisateur

Apple-Premiers__contacts_avec_iDVD_08

Apple-Mac_mini_Intel_User_Guide.pdf

Apple-Prise_en_charge_des_surfaces_de_controle_Logic_Express_8

Apple-mac_integration_basics_fr_107.pdf

Apple-Final-Cut-Pro-7-Niveau-1-Guide-de-preparation-a-l-examen

Apple-Logic9-examen-prep-fr.pdf-Logic-Pro-9-Niveau-1-Guide-de-preparation-a-l-examen

Apple-aperture_photography_fundamentals.pdf-Manuel-de-l-utilisateu

Apple-emac-memory.pdf-Manuel-de-l-utilisateur

Apple-Apple-Installation-et-configuration-de-votre-Power-Mac-G4

Apple-Guide_de_l_administrateur_d_Xsan_2.pdf

Apple-premiers_contacts_avec_imovie6.pdf

Apple-Tiger_Guide_Installation_et_de_configuration.pdf

Apple-Final-Cut-Pro-7-Level-One-Exam-Preparation-Guide-and-Practice-Exam

Apple-Open_Directory.pdf

Apple-Nike_+_iPod_User_guide

Apple-ard_admin_guide_2.2_fr.pdf

Apple-systemoverviewj.pdf-Japon

Apple-Xserve_TO_J070411.pdf-Japon

Apple-Mac_Pro_User_Guide.pdf

Apple-iMacG5_iSight_UG.pdf

Apple-premiers_contacts_avec_iwork_08.pdf

Apple-services_de_collaboration_2e_ed_10.4.pdf

Apple-iPhone_Bluetooth_Headset_Benutzerhandbuch.pdf

Apple-Guide_de_l_utilisateur_de_Keynote08.pdf

APPLE/Apple-Logic-Pro-9-Effectsrfr.pdf

Apple-Logic-Pro-9-Effectsrfr.pdf

Apple-iPod_shuffle_3rdGen_UG_F.pdf

Apple-iPod_classic_160Go_Guide_de_l_utilisateur.pdf

Apple-iBookG4GettingStarted.pdf

Apple-Administration_de_technologies_web_10.5.pdf

Apple-Compressor-4-User-Manual-fr

Apple-MainStage-User-Manual-fr.pdf

Apple-Logic_Pro_8.0_lbn_j.pdf

Apple-PowerBookG4_15inch1.67-1.5GHzUserGuide.pdf

Apple-MacBook_Pro_15inch_Mid2010_CH.pdf

Apple-LED_Cinema_Display_27-inch_UG.pdf

Apple-MacBook_Pro_15inch_Mid2009_RS.pdf

Apple-macbook_pro_13inch_early2011_f.pdf

Apple-iMac_Mid2010_UG_BR.pdf

Apple-iMac_Late2009_UG_J.pdf

Apple-iphone_user_guide-For-iOS-6-Software

Apple-iDVD5_Getting_Started.pdf

Apple-guide_des_fonctionnalites_de_l_ipod_touch.pdf

Apple_iPod_touch_User_Guide

Apple_macbook_pro_13inch_early2011_f

Apple_Guide_de_l_utilisateur_d_Utilitaire_RAID

Apple_Time_Capsule_Early2009_Setup_F

Apple_iphone_4s_finger_tips_guide_rs

Apple_iphone_upute_za_uporabu

Apple_ipad_user_guide_ta

Apple_iPod_touch_User_Guide

apple_earpods_user_guide

apple_iphone_gebruikershandleiding

apple_iphone_5_info

apple_iphone_brukerhandbok

apple_apple_tv_3rd_gen_setup_tw

apple_macbook_pro-retina-mid-2012-important_product_info_ch

apple_Macintosh-User-s-Guide-for-Macintosh-PowerBook-145

Apple_ipod_touch_user_guide_ta

Apple_TV_2nd_gen_Setup_Guide_h

Apple_ipod_touch_manual_del_usuario

Apple_iphone_4s_finger_tips_guide_tu

Apple_macbook_pro_retina_qs_th

Apple-Manuel_de_l'utilisateur_de_Final_Cut_Server

Apple-iMac_G5_de_lutilisateur

Apple-Cinema_Tools_4.0_User_Manual_F

Apple-Personal-LaserWriter300-User-s-Guide

Apple-QuickTake-100-User-s-Guide-for-Macintosh

Apple-User-s-Guide-Macintosh-LC-630-DOS-Compatible

Apple-iPhone_iOS3.1_User_Guide

Apple-iphone_4s_important_product_information_guide

Apple-iPod_shuffle_Features_Guide_F

Liste-documentation-apple

Apple-Premiers_contacts_avec_iMovie_08

Apple-macbook_pro-retina-mid-2012-important_product_info_br

Apple-macbook_pro-13-inch-mid-2012-important_product_info

Apple-macbook_air-11-inch_mid-2012-qs_br

Apple-Manuel_de_l_utilisateur_de_MainStage

Apple-Compressor_3_User_Manual_F

Apple-Color_1.0_User_Manual_F

Apple-guide_de_configuration_airport_express_4.2

Apple-TimeCapsule_SetupGuide

Apple-Instruments_et_effets_Logic_Express_8

Apple-Manuel_de_l_utilisateur_de_WaveBurner

Apple-Macmini_Guide_de_l'utilisateur

Apple-PowerMacG5_UserGuide

Disque dur, ATA parallèle Instructions de remplacement

Apple-final_cut_pro_x_logic_effects_ref_f

Apple-Leopard_Installationshandbok

Manuale Utente PowerBookG4

Apple-thunderbolt_display_getting_started_1e

Apple-Compressor-4-Benutzerhandbuch

Apple-macbook_air_11inch_mid2011_ug

Apple-macbook_air-mid-2012-important_product_info_j

Apple-iPod-nano-Guide-des-fonctionnalites

Apple-iPod-nano-Guide-des-fonctionnalites

Apple-iPod-nano-Guide-de-l-utilisateur-4eme-generation

Apple-iPod-nano-Guide-de-l-utilisateur-4eme-generation

Apple-Manuel_de_l_utilisateur_d_Utilitaire_de_reponse_d_impulsion

Apple-Aperture_2_Raccourcis_clavier

AppleTV_Setup-Guide

Apple-livetype_2_user_manual_f

Apple-imacG5_17inch_harddrive

Apple-macbook_air_guide_de_l_utilisateur

Apple-MacBook_Early_2008_Guide_de_l_utilisateur

Apple-Keynote-2-Guide-de-l-utilisateur

Apple-PowerBook-User-s-Guide-for-PowerBook-computers

Apple-Macintosh-Performa-User-s-Guide-5200CD-and-5300CD

Apple-Macintosh-Performa-User-s-Guide

Apple-Workgroup-Server-Guide

Apple-iPod-nano-Guide-des-fonctionnalites

Apple-iPad-User-Guide-For-iOS-5-1-Software

Apple-Boot-Camp-Guide-d-installation-et-de-configuration

Apple-iPod-nano-Guide-de-l-utilisateur-4eme-generation

Power Mac G5 Guide de l’utilisateur APPLE

Guide de l'utilisateur PAGE '08 APPLE

Guide de l'utilisateur KEYNOTE '09 APPLE

Guide de l'Utilisateur KEYNOTE '3 APPLE

Guide de l'Utilisateur UTILITAIRE RAID

Guide de l'Utilisateur Logic Studio

Power Mac G5 Guide de l’utilisateur APPLE

Guide de l'utilisateur PAGE '08 APPLE

Guide de l'utilisateur KEYNOTE '09 APPLE

Guide de l'Utilisateur KEYNOTE '3 APPLE

Guide de l'Utilisateur UTILITAIRE RAID

Guide de l'Utilisateur Logic Studio

Guide de l’utilisateur ipad Pour le logiciel iOS 5.1

PowerBook G4 Premiers Contacts APPLE

Guide de l'Utilisateur iphone pour le logiciel ios 5.1 APPLE

Guide de l’utilisateur ipad Pour le logiciel iOS 4,3

Guide de l’utilisateur iPod nano 5ème génération

Guide de l'utilisateur iPod Touch 2.2 APPLE

Guide de l’utilisateur QuickTime 7  Mac OS X 10.3.9 et ultérieur Windows XP et Windows 2000

Guide de l'utilisateur MacBook 13 pouces Mi 2010

Guide de l’utilisateur iPhone (Pour les logiciels iOS 4.2 et 4.3)

Guide-de-l-utilisateur-iPod-touch-pour-le-logiciel-ios-4-3-APPLE

Guide-de-l-utilisateur-iPad-2-pour-le-logiciel-ios-4-3-APPLE

Guide de déploiement en entreprise iPhone OS

Guide-de-l-administrateur-Apple-Remote-Desktop-3-1

Guide-de-l-utilisateur-Apple-Xserve-Diagnostics-Version-3X103

Guide-de-configuration-AirPort-Extreme-802.11n-5e-Generation

Guide-de-configuration-AirPort-Extreme-802-11n-5e-Generation

Guide-de-l-utilisateur-Capteur-Nike-iPod

Guide-de-l-utilisateur-iMac-21-5-pouces-et-27-pouces-mi-2011-APPLE

Guide-de-l-utilisateur-Apple-Qadministrator-4

Guide-d-installation-Apple-TV-3-eme-generation

User-Guide-iPad-For-ios-5-1-Software

Xsan 2 Administrator Guide for Xsan 2.3KApple Inc. © 2011 Apple Inc. All rights reserved. Under the copyright laws, this manual may not be copied, in whole or in part, without the written consent of Apple. The Apple logo is a trademark of Apple Inc., registered in the U.S. and other countries. Use of the “keyboard” Apple logo (Option-Shift-K) for commercial purposes without the prior written consent of Apple may constitute trademark infringement and unfair competition in violation of federal and state laws. Every effort has been made to ensure that the information in this manual is accurate. Apple is not responsible for printing or clerical errors. Apple 1 Infinite Loop Cupertino, CA 95014 408-996-1010 www.apple.com Apple, the Apple logo, Mac, the Mac logo, Macintosh, Mac OS, and Xsan are trademarks of Apple Inc., registered in the U.S. and other countries. Apple Remote Desktop, Finder, and Spotlight are trademarks of Apple Inc. StorNext is a registered trademark of Quantum Corporation. AIX is a trademark of IBM Corp., registered in the U.S. and other countries, and is being used under license. UNIX is a registered trademark of The Open Group. Other company and product names mentioned herein are trademarks of their respective companies. Mention of third-party products is for informational purposes only and constitutes neither an endorsement nor a recommendation. Apple assumes no responsibility with regard to the performance or use of these products. Simultaneously published in the United States and Canada. 019-2098/2011-06-3011 Preface: About this book 12 What’s new in Xsan 2 13 Version compatibility 13 Upgrade from an earlier version of Xsan 13 More information 14 Notation conventions 15 Chapter 1: Quick SAN setup 15 Is this chapter right for you? 16 Equipment you’ll need 16 What you need to know 17 SAN setup instructions 18 Step 1: Unpack and install the SAN hardware 18 Step 2: Connect the SAN networks 18 Step 3: Set up the client computers 21 Step 4: Set up the standby metadata controller 21 Step 5: Set up the RAID systems 22 Step 6: Create a metadata array 22 Step 7: Set Up the primary metadata controller 23 Step 8: Configure the SAN 27 Step 9: Create a SAN volume 29 Step 10: Add users and groups 30 What’s next? 31 Chapter 2: Overview of Xsan 32 Xsan SANs 33 Shared SAN volumes 33 Metadata controllers 33 Clients 33 Network connections 34 How Xsan storage is organized 34 LUNs 35 Storage pools 3 Contents4 Contents 35 Affinities and affinity tags 36 Volumes 36 Folders with affinities 37 How Xsan uses available storage 37 Metadata and journal data 37 Stripe at a higher level 38 Security 38 Expand storage 38 Xsan capacities 40 Chapter 3: Plan a SAN 40 Hardware and software requirements 40 Supported computers 41 Supported storage devices 41 Fibre Channel fabric 42 Ethernet TCP/IP network 43 Directory services 44 Outgoing mail service 44 Plan your SAN 45 Preliminary planning questions 45 Planning considerations and guidelines 51 Plan the Ethernet TCP/IP network 52 Use a private metadata network 52 Use switches instead of hubs 52 Plan the Fibre Channel network 52 Verify base Fibre Channel performance 52 If your Fibre Channel fabric is running slowly 53 Configure RAID systems 53 Install the latest firmware 54 Connect RAID systems to an Ethernet network 54 Choose RAID levels for LUNs 54 Adjust RAID system performance settings 56 Chapter 4: Set up a SAN 56 Connect computers and storage devices 56 Prepare LUNs 57 Use the server setup assistant to configure controllers 57 Manage users and groups with Xsan Admin 57 Use an existing Open Directory server 58 Use another directory server 58 Use Xsan Admin 58 Connect through a firewall 58 Xsan Admin preferencesContents 5 58 Get help 58 SAN and volume setup summary 59 Set up an Xsan volume on a SAN 59 Step 1: Set up the Fibre Channel network 59 Step 2: Set up the Ethernet networks 60 Step 3: Configure SAN computers to use a time server 61 Step 4: Set up SAN users and groups 62 Step 5: Set up RAID systems 62 Step 6: Create a metadata array 63 Step 7: Enable Xsan on clients and controllers 64 Step 8: Configure the SAN 65 Step 9: Create a volume 68 Step 10: (Optional) Set up SAN status notifications 68 Step 11: (Optional) Assign folders to affinity tags 68 Step 12: (Optional) Set user and group quotas 68 Use an Xsan administrator computer 69 Rename a SAN 69 Set up another SAN 69 Manage multiple SANs 70 Destroy a SAN 71 Chapter 5: Manage SAN storage 71 Add storage 72 Prepare LUNs 72 Find the drive modules that belong to a LUN 73 Add a volume to a SAN 74 Add a storage pool to a volume 75 Add LUNs to an affinity tag 77 Rearrange Fibre Channel connections 77 Set up a folder affinity 78 Change a folder’s affinity 79 Remove an affinity 79 Change advanced volume settings 80 Set the block allocation size 80 Change the volume allocation strategy 81 Enable or disable Spotlight on a volume 81 Enable extended attributes 82 Enable or disable access control lists 82 Change filename case sensitivity 83 Change the Windows ID mapping 83 Change advanced allocation and cache settings 83 Change storage pool settings 84 Change the exclusivity of an affinity tag6 Contents 84 Set the storage pool stripe breadth 84 Maintain SAN volumes 85 Rename a volume 85 Check volume fragmentation 85 Defragment a volume 86 Check the integrity of a volume 87 Repair a volume 88 Check RAID devices 88 Destroy a volume 89 Chapter 6: Manage clients and users 89 Add a client 91 Add an Xsan serial number 91 Move a client to a different SAN 92 Mount a volume on a client 93 Change mount options 93 Manage users and groups 94 Add SAN users 95 Delete SAN users 95 Create groups 96 Delete groups 96 Change group membership 96 Configure local home folders for network accounts 97 Control client and user access 97 Control file and folder access using the Finder 97 Control file and folder access using Xsan Admin 98 Unmount a volume on a client 99 Remove a client from a SAN 100 Map Windows user and group IDs 100 Set SAN user and group quotas 102 About Xsan quotas 103 Check user quota status 104 Help users check quotas 105 Manage client computers remotely 105 Control a client using screen sharing 106 Connect to a client using SSH in terminal 107 Chapter 7: Manage metadata controllers 109 Set controller failover priority 109 Switch to a standby metadata controller 110 Find out which controller is hosting a volume 110 List the volumes hosted by a controller 111 Change a controller’s IP addressContents 7 112 Make a standby controller the primary controller 112 Convert a controller to a client 112 Access controller computers remotely 113 Control a controller using screen sharing 113 Connect to a controller using SSH in Terminal 114 Monitor controller status 115 Chapter 8: Monitor SAN status 115 Check SAN status 116 Check volume status 116 Monitor RAID devices 117 Check free space 118 Graph SAN resource usage 119 Set up status notifications 120 View Xsan logs 121 Check volume clients 122 Chapter 9: Solve SAN problems 122 If you can’t connect to a computer using Xsan Admin 122 If you can’t enable or install the Xsan software 122 If computers aren’t listed in Xsan Admin 123 If you can’t mount a volume on a client 123 If you can’t unmount a volume on a client 123 If RAID LUNs aren’t accessible over Fibre Channel 123 If you have problems using command-line tools 123 If a LUN doesn’t have as much space as expected 123 If you can’t rename an Xsan volume in the Finder 124 If you can’t add a storage pool 124 If Fibre Channel performance is poor 124 If a client can’t use a volume after a Fibre Channel interruption 125 If you can’t add LUNs to a storage pool 125 If the capacity of a larger LUN is Listed as 2 terabytes 125 If file copying doesn’t finish 126 If a volume unexpectedly restarts 127 Appendix A : Upgrade to Xsan 2.3 127 Before you begin 127 If you’re not running Xsan 2.0 or later 127 Lion or Lion Server? 127 Which procedure? 128 Version compatibility 128 Upgrade your SAN software 128 Step 1: Back up your SAN volumes8 Contents 128 Step 2: Disable Spotlight on all volumes 129 Step 3: Upgrade the primary controller to Mac OS X Lion Server 129 Step 4: Upgrade the remaining controllers 130 Step 5: Reestablish Open Directory replicas 130 Step 6: Upgrade the SAN clients 131 Step 7: Enable extended attributes 131 Step 8: Change filename case sensitivity 132 Step 9: Reenable Spotlight 132 Upgrade SAN hardware and software 133 Step 1: Back up your SAN volumes 133 Step 2: Disable Spotlight on all volumes 133 Step 3: Adjust volume failover priorities 133 Step 4: Convert all standby controllers to clients 134 Step 5: Unmount and stop all volumes 134 Step 6: Connect new Macs to the SAN 134 Step 7: Migrate the primary metadata controller 135 Step 8: Migrate former standby controllers 136 Step 9: Convert clients to standby controllers 136 Step 10: Migrate or upgrade SAN clients 138 Step 11: Enable extended attributes 138 Step 12: Change filename case sensitivity 139 Step 13: Reenable Spotlight 139 Step 14: Recreate your MultiSAN configuration 140 Appendix B: Combine Xsan controllers and StorNext clients 140 Compatible software versions 140 Terminology 141 License 141 Add StorNext clients to an Xsan SAN 142 Appendix C: Use command-line tools 142 Use shell commands 142 Send commands to remote computers 143 View the man pages 143 Notation conventions 143 Install Xsan from the command line 145 Xsan commands 145 View or change volume and storage pool settings (cvadmin) 149 Manipulate affinity tags (cvaffinity) 149 Copy files or folders (cvcp) 150 Check or repair a volume (cvfsck) 151 Label, list, and unlabel LUNs (cvlabel) 152 Create a folder and assign an affinity (cvmkdir)Contents 9 153 Create and preallocate a file (cvmkfile) 153 Initialize a volume (cvmkfs) 154 Apply volume configuration changes (cvupdatefs) 154 Defragment a file, folder, or volume (snfsdefrag) 156 Control the Xsan file system (xsanctl) 157 Mount an Xsan volume 157 Unmount an Xsan volume 158 View logs 158 Xsan configuration files 159 Glossary 162 Index11 Use this guide to learn how to use Xsan 2 to set up and manage volumes on a storage area network. This guide shows how to use Xsan 2 to combine RAID arrays into large, easy-to-expand volumes of storage that clients use like local disks, but which are actually shared over a high-speed Fibre Channel fabric. The guide is updated for Xsan 2 version 2.3 and contains the following sections.  Chapter 1,“Quick SAN setup,” has instructions for setting up a storage area network (SAN) for the first time using new computers with Mac OS X Lion or Lion Server, new RAID systems, and a default SAN configuration.  Chapter 2,“Overview of Xsan,” provides an overview of Xsan and how you can use it to organize RAID arrays into shared volumes of storage.  Chapter 3,“Plan a SAN,” describes hardware and software requirements, and offers SAN planning guidelines.  Chapter 4,“Set up a SAN,” shows the basic steps for setting up a SAN.  Chapter 5,“Manage SAN storage,” contains instructions for expanding storage, creating folders with affinities, changing volume and storage pool settings, and checking, defragmenting, and repairing SAN volumes.  Chapter 6,“Manage clients and users,” shows how to add client computers to a SAN, mount volumes on clients, control client and user access to SAN files, and control user space through quotas.  Chapter 7,“Manage metadata controllers,” contains information about managing volume metadata controllers.  Chapter 8,“Monitor SAN status,” shows how to monitor and automatically report the condition of a SAN.  Chapter 9,“Solve SAN problems,” lists solutions to common problems you might encounter.  Appendix A,“Upgrade to Xsan 2.3,” explains how to upgrade from earlier versions of Xsan. Preface About this book12 Preface About this book  Appendix B,“Combine Xsan controllers and StorNext clients,” contains information to help you use Xsan metadata controllers with Quantum StorNext clients.  Appendix C,“Use command-line tools” describes command-line tools and configuration files you can use to manage an Xsan SAN from the Terminal app. What’s new in Xsan 2 Xsan 2 offers these new features and capabilities:  The Xsan Admin app is redesigned to simplify SAN management.  Xsan Admin enables you to turn on drive activity lights to identify LUNs.  A volume setup assistant guides you through the process of creating volumes for common purposes such as video editing and file services.  The volume setup assistant also organizes available storage into storage pools for you, based on the way you plan to use the volume.  More than one storage pool can have the same affinity tag.  Each volume has a separate failover priority.  The Xsan file system supports extended attributes for Macs with Xsan 2.3 or Xsan 2.2. Volumes created with Xsan 2.3 use extended attributes by default.  Xsan 2.3: The Xsan file system is built into Mac OS X Lion. Any Mac that has Lion and the requisite Ethernet and Fibre Channel connections can access Xsan volumes.  Xsan 2.3: Mac OS X Lion includes an Xsan pane in System Preferences. It lets users with administrator accounts on their computers enable and disable the Xsan file system, mount and unmount Xsan volumes, and see basic SAN information such as the SAN name and the SAN administrator name and email address.  Xsan 2.3: Mac OS X Lion includes support for the Asymmetric Logical Unit Access (ALUA) standard for multipathing and failover. Support for this standard multipathing implementation allows Xsan to be used with a variety of Fibre Channel RAID storage arrays.  Xsan 2.3: An Xsan 2.3 SAN can also include client computers that have Mac OS X or Mac OS X Server version 10.6 Snow Leopard and Xsan 2.2.1 installed.  Xsan 2.3: For improved performance and simplicity, you can now have Xsan volumes that aren’t case sensitive. These volumes, like traditional Mac volumes, do not distinguish between uppercase and lowercase letters in filenames.  Xsan 2.3: An Xsan volume can have a separate storage pool for journal data, which may improve performance.Preface About this book 13 Version compatibility The following table shows the compatibility of Xsan 2.3 metadata controllers and clients with earlier Xsan versions and with StorNext controllers and clients. For the latest information about compatibility with StorNext controllers and clients, see the AppleCare Support article at support.apple.com/kb/HT1517. Controller Client Compatible Xsan 2.3 Xsan 2.3 Yes Xsan 2.2.1 with Mac OS X or Mac OS X Server v10.6 Snow Leopard Yes Xsan 2.2.1 with Mac OS X v10.5 Leopard or Mac OS X Server v10.5 Leopard No Xsan 2.2 or earlier No Upgrade from an earlier version of Xsan For information about upgrading your SAN storage to Xsan 2.3 from Xsan 2.2.1—including precautions to take before upgrading and tips for upgrading with the least impact on existing storage—see Appendix A,“Upgrade to Xsan 2.3.” More information For more information about Xsan, consult these resources: Xsan website (www.apple.com/xsan/) Get information about planning for, installing, setting up, and upgrading to Xsan 2.3. Xsan Support website (www.apple.com/support/xsan/) Find articles about Xsan from Apple’s support organization. Apple Discussions website (discussions.apple.com) Join a discussion group to share questions, knowledge, and advice with other Xsan administrators. Apple Training and Certification website (training.apple.com) Find instructor-led and self-paced courses for improving your Xsan administration skills. Apple Mailing Lists website (www.lists.apple.com) Subscribe to mailing lists so you can communicate with other Xsan administrators by email.14 Preface About this book Notation conventions The following conventions are used in this book where command-line tools are described. Notation Indicates fixed-width font A command or other text entered in a Terminal window $ A shell prompt [text_in_brackets] An optional parameter (one|other) Alternative parameters (enter one or the other) italicized A parameter you must replace with a value [...] A parameter that can be repeated A displayed value that depends on your SAN configuration15 Follow the instructions in this chapter to set up a volume on a storage area network (SAN) using Xsan 2. Is this chapter right for you? To keep setup instructions simple, this chapter assumes:  You’re setting up a SAN for the first time using new computers and RAID systems.  Your SAN computers are running Mac OS X Lion or Lion Server.  You’ll let Xsan set up a SAN directory service on your metadata controllers.  You’ll use the Xsan Admin app to create SAN user accounts.  You’ll choose a standard SAN volume type and let Xsan organize your storage pools.  You’ll let the Xsan setup assistant configure your private metadata network settings. To reuse existing computers while following this chapter, perform a clean installation of Mac OS X Lion or Lion Server on each computer before you begin. You can add more SAN clients after setting up your SAN, including clients that have Mac OS X or Mac OS X Server version 10.6 Snow Leopard. For information, see “Add a client” on page 89. If you want more control over the underlying organization of your SAN volumes or directory services, you can find more general instructions in the next three chapters. If you already have a SAN that you want to upgrade, you’ll find instructions in Appendix A,“Upgrade to Xsan 2.3.” 1 Quick SAN setupEquipment you’ll need To set up a new SAN using the instructions in this chapter, you need:  Fibre Channel RAID storage devices for SAN storage  Two computers that have Mac OS X Lion Server to act as SAN metadata controllers  One or more SAN client computers that have Mac OS X Lion or Lion Server  An Intel processor and at least 2 GB of RAM in each SAN computer  An additional 2 GB of RAM per SAN volume in each metadata controller  Two Ethernet ports for each SAN computer  An Apple Fibre Channel card or other Fibre Channel adapter for each SAN computer  A Fibre Channel switch and cables for all storage devices and computers  An Ethernet switch and cables for the private SAN metadata network  A second Ethernet switch and cables for public intranet and Internet access  An equipment rack if your RAID storage systems, SAN computers, or switches are designed to mount in one A list of qualified RAID systems and Fibre Channel switches is available on the Xsan website at www.apple.com/xsan/. What you need to know You need to provide the following information when you set up your SAN:  A static (fixed) public IP address, subnet mask, router address, and DNS server address for each computer on the SAN. You can enter this information manually or configure a DHCP server to provide it. If you want the DHCP server to provide IP addresses, be sure it always assigns the same IP address to each SAN computer.  A single user name and password for the administrator account on all SAN computers.  A user name and password for each user who will log in to a client computer.  A unique name for each computer (recommended) 16 Chapter 1 Quick SAN setupChapter 1 Quick SAN setup 17 The following illustration shows the hardware components of an Xsan SAN. Metadata controller Clients Standby controller Metadata RAID array (LUN) Fibre Channel switch Ethernet (public) Ethernet (private) Intranet/ Internet RAID arrays (LUNs) Ethernet switches SAN setup instructions Use the instructions on the following pages to set up your SAN for the first time. Summary 1 Unpack and Install the SAN Hardware 2 Connect the SAN Networks 3 Set Up the Client Computers 4 Set Up the Standby Metadata Controller 5 Set Up the RAID Systems 6 Create a Metadata Array 7 Set Up the Primary Metadata Controller 8 Configure the SAN 9 Create a SAN VolumeStep 1: Unpack and install the SAN hardware To install the components of your SAN, follow the instructions that come with each computer, RAID storage system, and switch. Don’t turn on any equipment until instructed to do so. Install the hardware: 1 Unpack each computer that will be part of the SAN. 2 If you need to install Fibre Channel or Ethernet cards or adapters for any of the computers, follow the instructions that come with the computer to install the card or adapter. 3 Unpack the RAID systems used for SAN storage and follow the instructions that come with the systems to install them in a rack. 4 Unpack and install the Fibre Channel switch, following the instructions that come with the switch. 5 Unpack and install the Ethernet switches for the SAN’s private metadata network and public intranet or Internet connections. Step 2: Connect the SAN networks Set up your switches and use Fibre Channel and Ethernet cables to connect the SAN computers and storage devices to the Fibre Channel and Ethernet switches. Connect the SAN networks: 1 Turn on the Fibre Channel switch and follow the manufacturer’s instructions to set it up; then connect each SAN computer to the switch using one or two Fibre Channel cables. 2 Connect the Fibre Channel ports on each RAID storage unit to the Fibre Channel switch. For details, see the instructions that come with the RAID system. 3 Turn on the Ethernet switches and connect the first Ethernet port on each SAN computer to the public Ethernet switch using an Ethernet cable. 4 Connect the second Ethernet port on each SAN computer to the private metadata Ethernet switch using a second Ethernet cable. 5 Connect the Ethernet ports on each RAID storage system to the public Ethernet switch. For details, see the instructions that come with the RAID storage system. Step 3: Set up the client computers Now you’ll go to each client computer to set up an administrator account, configure network settings, and enable the Xsan software. The procedure differs based on whether the client computer has Mac OS X Lion or Lion Server installed and ready for initial setup. 18 Chapter 1 Quick SAN setupChapter 1 Quick SAN setup 19 Use one of the next two procedures—“If a Client Has Mac OS X Lion Installed” or “If a Client Has Mac OS X Lion Server Installed”—as appropriate, with each client computer on the SAN. When you finish setting up the client computers, they’re ready to join the SAN and are detected during SAN setup. After you finish setting up client computers, go to “Step 4: Set up the standby metadata controller” on page 21. If a client has Mac OS X Lion installed: 1 Turn on the client computer. 2 Follow the Mac setup assistant’s onscreen instructions to set up the computer, paying special attention to the information in the following panes: Your Internet Connection: Choose a connection type from the pop-up menu and enter the appropriate settings for the client computer. You can choose:  Manually, and then enter the static public IP address, subnet mask, router address, and DNS server address for the client computer  Using DHCP with manual address, and then enter the client computer’s IP address if your DHCP server provides other network connection settings  Using DHCP, if your DHCP server provides the client computer with a static IP address and other connection settings Select Your Admin Account: If this pane appears, select “Create a local user account to administer this computer.” Create Your Computer Account: Enter the same administrator name and password on all computers in the SAN. 3 When the Mac setup assistant finishes and the Finder appears, choose System Preferences from the Apple menu () . 4 Click Network and select the first Ethernet port, which should be connected to your public intranet and the Internet. 5 Choose a configuration method from the pop-up menu, and then enter the appropriate settings for the client computer. You can choose:  Manually, and then enter the static public IP address, subnet mask, router address, and DNS server address for the client computer  Using DHCP with manual address, and then enter the client computer’s IP address if your DHCP server provides other network connection settings  Using DHCP, if your DHCP server provides the client computer with a static IP address and other connection settings Don’t configure the port connected to the private metadata network—the Xsan setup assistant configures it for you.6 In the Date & Time pane of System Preferences, make sure the computer is configured to set the date and time automatically using a time server. 7 In the Sharing pane of System Preferences, enter a computer name that’s different from other SAN computer names. Giving each SAN computer a unique name is optional but allows you to distinguish them in Xsan Admin. 8 In the Xsan pane of System Preferences, click Enable Xsan. The client computer can now join the SAN and is detected by the primary metadata controller during SAN setup. If the client has Mac OS X Lion Server installed: 1 Turn on the client computer. 2 Follow the server setup assistant’s onscreen instructions to set up the computer, paying special attention to the information in the following panes: Administrator Account: Enter the same account name and password on all client computers. Time Zone: Configure the computer to use a network time server, which sets the date and time automatically. Xsan: Select “Configure as Xsan Metadata Controller or Client.” Xsan Computer Type: Select “Configure as Xsan Client.” Network: Enable only the public Ethernet port (Ethernet 1 at the top of the list). Choose a configuration method from the pop-up menu and enter the appropriate settings for the client computer. You can choose:  Manually, and then enter the static public IP address, subnet mask, router address, and DNS server address for the client computer  Using DHCP with manual address, and then enter the client computer’s IP address if your DHCP server provides other network connection settings  Connecting to Your Mac: Enter a computer name that’s different from other SAN computer names. Giving each SAN computer a unique name is optional but allows you to distinguish them in Xsan Admin. Don’t configure the Ethernet port connected to the private metadata network (Ethernet 2). The Xsan setup assistant configures it for you. The client computer can now join the SAN and is detected by the primary metadata controller during SAN setup. 20 Chapter 1 Quick SAN setupChapter 1 Quick SAN setup 21 Step 4: Set up the standby metadata controller Now set up the standby metadata controller. This computer must have Mac OS X Lion Server installed but not yet set up. Set up the standby controller: 1 Turn on the computer you’re using as the standby metadata controller. 2 Follow the server setup assistant’s onscreen instructions to configure the computer, paying special attention to the settings in the following panes: Administrator Account: Enter the same account name and password that you used on your client computers. Time Zone: Configure the computer to use a network time server, which sets the date and time automatically. Xsan: Select “Configure as Xsan Metadata Controller or Client.” Xsan Computer Type: Select “Configure as Standby Xsan Metadata Controller.” Network: Enable only the public Ethernet port (Ethernet 1 at the top of the list). Choose a configuration method from the pop-up menu and enter the appropriate settings for the computer. You can choose:  Manually, and enter the static public IP address, subnet mask, router address, and DNS server address for the computer  Using DHCP with manual address, and enter the computer’s IP address if your DHCP server provides other TCP/IP connection settings The standby metadata controller can now join the SAN and is detected by the primary metadata controller during SAN setup. Step 5: Set up the RAID systems Now configure your RAID systems. Xsan sees the RAID arrays provided by the RAID systems as Fibre Channel logical unit numbers (LUNs) that can be combined to create SAN volumes. Set up the RAID systems: 1 Follow the instructions that come with your RAID systems to turn them on and configure their network, management, and security settings. 2 If your RAID systems come with RAID sets already configured, they’re detected during SAN setup, and you can skip to “Step 6: Create a metadata array” on page 22; otherwise, use the management software that comes with the RAID system to create arrays that are the same size, leaving three drives on one system unassigned so you can create a small, separate metadata LUN as described in the next step. Setup scripts for Promise RAID systems are available at www.apple.com/support/xsan/.Step 6: Create a metadata array Ten GB of disk space is enough to store the metadata for a volume containing 10 million files, so a two-drive RAID 1 (mirrored) array is generally large enough to store the metadata for your SAN volume. If you dedicate a spare drive to this array to guarantee availability, three drives are adequate for your SAN metadata. If your RAID arrays consist of four or more drives, you can follow these steps to convert an existing array into a small metadata array so you can reuse the extra drives. If you’ve set up a Promise RAID system using a script from www.apple.com/support/xsan/, you should have a two-drive RAID 1 array for metadata, and you can skip to “Step 7: Set Up the primary metadata controller”on page 22. Create a metadata array: 1 If you don’t have three spare drives, or if the drives in your RAID systems belong to RAID arrays, use the management software for your RAID system to delete an existing array. You can do this on the standby metadata controller or on a client that you’ve already set up. 2 Use two of the drives to create a two-drive RAID 1 (mirrored) array. 3 Assign a third drive as a dedicated spare for the array. You can use leftover drives from the original array to create a separate array, or save them for use as spares. You now have a new two-drive RAID 1 array for storing SAN metadata. You add this LUN to your metadata storage pool when you create your SAN volume. Step 7: Set Up the primary metadata controller Now that you’ve prepared your SAN clients, standby metadata controller, and RAID storage systems, you can set up the primary metadata controller. This computer must have Mac OS X Lion Server installed but not yet set up. Set up the primary controller: 1 Turn on the computer that will be the primary metadata controller. 2 Follow the server setup assistant’s onscreen instructions to configure the computer, paying special attention to the following panes: Administrator Account: Enter the same account name and password that you used on your client computers. Time Zone: Configure the computer to use a network time server, which sets the date and time automatically. Xsan: Select “Configure as Xsan Metadata Controller or Client.” 22 Chapter 1 Quick SAN setupChapter 1 Quick SAN setup 23 Xsan Controller Type: Select “Configure as Primary Xsan Metadata Controller.” Network: Enable only the public Ethernet port (Ethernet 1 at the top of the list). Choose a configuration method from the pop-up menu and enter the appropriate settings for the client computer. See “What you need to know” on page 16. You can choose:  Manually, and enter the static public IP address, subnet mask, and router address for the computer  Using DHCP with manual address, and enter the computer’s IP address if your DHCP server provides other TCP/IP connection settings Users and Groups: Select “Manage users and groups with Xsan Admin.” Step 8: Configure the SAN After basic server configuration and Xsan installation are complete, open Xsan Admin. The Xsan setup assistant appears. Follow these steps to enter basic SAN settings. Configure the SAN: 1 In the Introduction pane, click Continue.2 In the Initial SAN Setup pane, select “Configure new SAN.” 3 In the SAN Settings pane, enter a name for the SAN and the SAN administrator’s name and email address. 24 Chapter 1 Quick SAN setupChapter 1 Quick SAN setup 25 4 In the Add Computers pane, make sure all computers that you want to be in the SAN are selected. If a computer you want to include isn’t listed, make sure Xsan is enabled in that computer’s Xsan preferences, check that it’s connected to both Ethernet networks, and verify the network settings in the computer’s Network preferences. You can also click Add Remote Computer to add computers manually. 5 In the Authenticate SAN Computers pane, select “Use same authentication information for all SAN Computers” and enter the user account name and password for the administrator account you created on the clients and the standby metadata controller.6 In the Choose Metadata Controllers pane, select your primary and standby metadata controllers and deselect any client-only computers that appear in the list. 7 In the Private Metadata Network pane, select “Yes, manage private Ethernet network settings.” 26 Chapter 1 Quick SAN setupChapter 1 Quick SAN setup 27 8 Review the Summary pane, and if all settings are correct, click Continue. To change a setting, click Go Back until you reach the pane where you can correct the setting. Then click Continue until you return to the Summary pane. Step 9: Create a SAN volume When the Xsan setup assistant finishes basic SAN configuration, it asks if you want to create a volume. Create a volume: 1 In the “Create Volume” pane, select “Create a volume now” and click Continue.2 In the “Volume Name and Type” pane, enter a name for the volume and choose a volume type that matches the type of work the volume will support. 3 If the Label LUNs pane appears, select “Automatically label all unlabeled LUNs with prefix” and click Continue. 4 In the Configure Volume Affinities pane, drag LUNs from the left column to the corresponding affinity tag in the right column. a Drag the special metadata LUN you created (in “Step 6: Create a metadata array”) to the MetadataAndJournal affinity tag. b Drag your other LUNs to the other affinity tags. To avoid wasting storage, all LUNs assigned to an affinity tag should be the same size. c If you’re left with any affinity tags that contain no LUNs, delete them. d When you finish, click Continue. 28 Chapter 1 Quick SAN setupChapter 1 Quick SAN setup 29 5 When the Volume Failover Priority pane appears, you can change the failover order for the volume you’re creating, and then click Continue. 6 In the Setup Complete pane, click Continue. Xsan Admin displays a summary of your SAN configuration, and the new volume is mounted and ready to use in the Finder on all clients and metadata controllers. Step 10: Add users and groups When your volume is ready, the SAN setup assistant closes and Xsan Admin opens. You use Xsan Admin to add users and groups to your SAN. Add a user or group: m In Xsan Admin, select “Users and Groups” in the SAN Assets list and then click the Add button (+) in the lower right corner of the window.What’s next? Your SAN volume is now ready to use. When SAN users log in to client computers, they’ll see the volume in the Finder. For information about using and managing the SAN, see the other chapters of this guide. They cover topics such as:  Controlling access to files and folders on SAN volumes  Setting folder affinities  Managing available space with user quotas  Monitoring the status of the SAN and its volumes You can also find information about these and other tasks in the onscreen help. Open Xsan Admin and choose Help > Xsan Admin Help. 30 Chapter 1 Quick SAN setup31 Learn about storage area networks (SANs) and how Xsan helps you set one up. Read this chapter for an overview of Xsan and how you can use it to set up a SAN to provide fast, shared storage. SAN_ Volume Mac OS X Xsan lets you combine RAID arrays into volumes clients use like local disks. File data moves over Fibre Channel RAID arrays (LUNs) Storage pools 2 Overview of XsanXsan SANs A SAN is a way of connecting computers and storage devices so computers have fast, shared access to files while making it easy for administrators to expand storage capacity. An Xsan SAN consists of:  Shared data volumes  RAID systems that provide storage space that is protected from disk failure  At least one computer acting as a metadata controller that combines RAID arrays and presents their storage to clients as volumes that behave like local disks  Client computers that access storage in accordance with established permissions and quotas  Underlying Fibre Channel and Ethernet networks The following illustration shows the hardware components of an Xsan SAN. Metadata controller Clients Standby controller Metadata RAID array (LUN) Fibre Channel switch Ethernet (public) Ethernet (private) Intranet/ Internet RAID arrays (LUNs) Ethernet switches 32 Chapter 2 Overview of XsanChapter 2 Overview of Xsan 33 Shared SAN volumes A user or application on a client computer accesses shared SAN storage the way they would access a local volume. Xsan volumes are logical disks made up of pools of RAID arrays. The elements you combine to create an Xsan volume are described in “How Xsan storage is organized” on page 34. Metadata controllers When you set up an Xsan SAN, you assign at least one computer to act as the metadata controller. The controller manages volume metadata, maintains a file system journal, and controls concurrent access to files. Metadata includes such information as where files are stored and what portions of available storage are allocated to new files. To guarantee volume availability, a SAN should include more than one metadata controller, as shown in the illustration on page 32. If the primary controller fails, the standby controller takes over. Clients The computers that users or applications use to access SAN volumes are called clients. Clients exchange metadata with controllers over the private Ethernet network but use Fibre Channel to send and retrieve file data to and from the RAID systems that provide storage for the volumes. Network connections Xsan uses the following independent networks to connect storage devices, metadata controllers, and client computers: a Fibre Channel network and two Ethernet networks. Fibre Channel Xsan moves data between clients and SAN volumes over high-speed Fibre Channel connections. Controllers also use a Fibre Channel connection to move metadata to and from the volume. Xsan can take advantage of multiple Fibre Channel connections between clients and storage. Xsan can alternate between connections for each read and write, or it can assign each RAID array in a volume to a connection when the volume is mounted. Ethernet Xsan controllers and clients exchange file system metadata over a separate, private Ethernet network. (Controllers use Fibre Channel to read and write metadata on a volume.) To prevent Internet or intranet traffic from interfering with metadata communications, set up separate public (Internet) and private (metadata) Ethernet networks, as shown in the illustration on page 32.How Xsan storage is organized Although an Xsan volume mounted on a client computer looks like a single disk, it consists of multiple physical disks combined on several levels using RAID techniques. The following illustration shows an example of how disk space provided by drive modules in several RAID systems is combined into a volume that users see as a large local disk. RAID Arrays (LUNs) Data striping across LUNs Storage pools Affinity tags Folder affinities SAN volume Video Video Audio Other Metadata and journal Video Other Audio The following paragraphs describe these elements and how you combine them to create shared Xsan volumes. LUNs The smallest storage element you work with in Xsan is a logical storage device called a SCSI logical unit number, or LUN. A LUN represents a group of drives combined into a RAID array. You create a LUN when you create a RAID array on a RAID storage device. The RAID system combines physical drives into an array based on the RAID scheme you choose. Each array appears on the Fiber Channel network as a LUN. If the standard RAID arrays on your RAID systems aren’t right for your application, you can use the RAID system management software to recreate arrays based on other RAID schemes or different numbers of drive modules. For information about other RAID schemes, see “Choose RAID schemes for LUNs” on page 47. 34 Chapter 2 Overview of XsanChapter 2 Overview of Xsan 35 The illustration on page 34 shows eight LUNs. The LUN that stores metadata and journal information uses RAID level 1 (mirrored) to prevent metadata loss. One LUN stores users’ data on a RAID 0 array (striping only) for best speed and storage efficiency but no data protection. The other data LUNs use RAID 5 (distributed parity) for high performance and storage efficiency with data protection. Xsan sees the RAID arrays as LUNs that can be combined to create a volume. Your RAID LUNs are labeled and initialized for use with the Xsan file system when you use Xsan Admin to set up a volume. Storage pools LUNs are combined to form storage pools. A storage pool in a small volume might consist of a single RAID array, but a larger volume might consist of several storage pools each of which includes several arrays. Xsan distributes file data in parallel across the LUNs in a storage pool using a RAID 0 (striping) scheme. So, you can improve a client’s access speed by distributing available storage over several LUNs in a storage pool. You can set up storage pools that have different performance or recoverability characteristics based on the RAID level of their LUNs, and assign folders to them using affinities. Users can then select where to store files based on their need for speed or safety. See “Folders with affinities” on page 36. The illustration on page 34 shows eight LUNs combined into five storage pools. One pool uses a single RAID 0 array (fast, but not recoverable). Three other pools use multiple RAID 5 arrays (not as fast, but recoverable), and Xsan stripes data across the LUNs in each storage pool. You use Xsan Admin to add available LUNs to storage pools. Affinities and affinity tags An affinity associates a folder with specific storage pools. When you assign an affinity to a folder, you guarantee that files placed in the folder are stored on a storage pool that has the corresponding affinity tag. An affinity tag groups storage pools based on performance and recoverability characteristics. More than one storage pool can have the same affinity tag. Xsan distributes the contents of a folder with a specific affinity among the storage pools that have that affinity tag. This strategy improves performance when users simultaneously read and write files in the same folder, because the read and write operations are distributed among the storage pools and their component LUNs.You use Xsan Admin to assign affinity tags to storage pools and associate folders with those affinity tags. Volumes Storage pools are combined to create the volumes that users see. From the user’s perspective, the SAN volume looks and behaves like a large local disk, except that:  The size of the volume can grow as you add underlying arrays or storage pools  Multiple users on the SAN can access files on the volume at the same time In the illustration on page 34, five storage pools are combined to create a single shared volume. You use Xsan Admin to create volumes and mount them on client computers. The following screen shot shows how LUNs, storage pools, and volumes look as you organize them in Xsan Admin. This example shows a SAN with a single shared volume named “SanVol.” Storage for the volume is provided by two storage pools, “MetadataAndJournal” and “Data1,” the first based on a single LUN and the other on two LUNs. Volume Storage pool LUN Folders with affinities To control which storage pools are used to store specific files (for example, to provide different levels of service for different users or apps), you can associate a folder on an Xsan volume with an affinity tag that’s assigned to storage pools that make up the volume. 36 Chapter 2 Overview of XsanChapter 2 Overview of Xsan 37 For example, you can associate some folders with an affinity whose storage pools have faster LUNs, and associate other folders with an affinity whose storage pools have safer LUNs. Users can choose between faster and safer storage by putting files in the appropriate folder. In the illustration on page 34, the Other folder has an affinity for the faster storage pool based on a RAID 0 array. Any file that a user copies into the Other folder is stored on the faster array. The Video and Audio folders are associated with the more secure RAID 5 storage. How Xsan uses available storage Xsan stores user files and file system data on SAN volumes, and stripes data across the LUNs in a volume for better performance. Metadata and journal data Xsan records information about the files in an Xsan volume using metadata files and file system journals. File system metadata includes information such as which specific parts of which disks are used to store a file and whether the file is being accessed. The journal data includes a record of file system transactions that help ensure the integrity of files in the event of a failure. These files are managed by the Xsan metadata controller but are stored on SAN volumes, not on the controller itself. Metadata is stored on the first storage pool you add to a volume. Journal data can also be stored on the same storage pool as metadata, or you can use a separate storage pool for journal data. You must have journal data on only one storage pool. Stripe at a higher level When a RAID system writes a file using a RAID 0 (striping) scheme, it breaks the file into segments and spreads them across disk drives in the RAID array. This improves performance by writing parts of the file in parallel (instead of one part at a time) to disks in the array. Xsan applies this same technique in the storage hierarchy. Within each storage pool in a volume, Xsan stripes file data across the LUNs that make up the storage pool. Performance is improved because data is written in parallel. You can tune SAN performance to suit a critical application by adjusting the amount of data written to each LUN in a storage pool (the stripe breadth).Security There are several ways you can control access to a SAN volume:  Unmount a volume on client computers that shouldn’t have access to it. However, users who have administrator accounts on client computers with Mac OS X Lion or Lion Server can browse and mount SAN volumes.  Specify owner, group, and general access permissions in Xsan Admin.  Specify owner, group, and general access permissions in the Finder.  Control user access to files and folders on a volume, by setting up access control lists (ACLs) in Xsan Admin.  Set up zones in the underlying Fibre Channel network, to segregate users and volumes. Expand storage There are two ways you can add free space to an Xsan volume:  Add RAID systems (new LUNs) to an affinity tag  Add new storage pools to the volume Both methods unmount and remount the volume on clients, so choose a time that’s convenient for your SAN users. You can also add volumes to a SAN at any time. For information about expanding Xsan storage, see “Add storage” on page 71. Xsan capacities The following table lists limits and capacities for Xsan volumes. Parameter Maximum Number of volumes on a SAN 16 Number of storage pools in a volume 512 Number of LUNs in a storage pool 32 Number of LUNs in a volume 512 Number of files in a volume 4,294,967,296 LUN size Limited by the size of the RAID array Volume size Limited by the number and size of LUNs File size Approximately 2 63 bytes Volume name length 70 characters (A–Z, a–z, 0–9, and _ ) 38 Chapter 2 Overview of XsanChapter 2 Overview of Xsan 39 Parameter Maximum File or folder name length 251 ASCII characters Storage pool name length 255 ASCII characters Affinity name length 255 ASCII characters LUN name (label or disk name) 242 ASCII characters40 Learn Xsan hardware and software requirements and planning guidelines and performance tips to help you design a SAN for your needs. This chapter contains:  Xsan hardware and software requirements (below)  SAN planning guidelines (page 44) Hardware and software requirements Your SAN environment must satisfy requirements in these areas:  Supported computers  Supported storage devices  Fibre Channel fabric, adapters, and switches  Ethernet network  Directory services (optional)  Outgoing mail service (optional) Supported computers To join an Xsan 2.3 SAN, computers must meet the following minimum requirements. Base systems  Clients and controllers must be Macs that have Intel processors and can be connected to Fibre Channel fabric. Memory  Client computers must have at least 2 GB of RAM.  Computers used as metadata controllers must have at least 2 GB of RAM for Mac OS X Lion Server plus an additional 2 GB of RAM for each SAN volume hosted by the controller. For example, a controller should have 4 GB of RAM to host one volume, or 6 GB for two volumes. 3 Plan a SANChapter 3 Plan a SAN 41 Supported operating systems Computers with Mac OS X Lion or Lion Server can be used as Xsan 2.3 metadata controllers and clients. Mac OS X Lion Server is recommended for metadata controllers. Xsan 2.3 is included with Mac OS X Lion and Lion Server. To join an Xsan 2.3 SAN, Windows, AIX, IRIX, Linux, and Solaris clients must be running Quantum’s StorNext File System. For version compatibility information, see “Version compatibility” on page 13. Supported storage devices Use only Apple-qualified RAID systems or ALUA-compliant RAID systems for storage devices. For the latest information about qualified RAID systems, see the Xsan webpage at www.apple.com/xsan/. Important: Be sure to install the latest firmware update on your RAID systems before you use them with Xsan. Fibre Channel fabric Unlike file system metadata, which controllers and clients exchange over Ethernet, file content in an Xsan SAN is transferred over Fibre Channel connections (as is metadata that controllers access on a volume). The computers, storage devices, and switches are connected with Fibre Channel cables to form a Fibre Channel fabric. To set up the connections, you need:  An Apple Fibre Channel card or other Fibre Channel adapter for each client and controller computer  A supported Fibre Channel switch  Fibre Channel cables connecting computers and storage devices to the switches to form a Fibre Channel fabric Fibre Channel cards or adapters Install an Apple Fibre Channel PCI card or attach a Fibre Channel adapter to a compatible port of each Mac that connects to the SAN. Fibre Channel switches Fibre Channel switches from Brocade, Cisco, and QLogic have been tested with Xsan and the Apple Fibre Channel PCI, PCI-X, and PCI-E cards. For the latest information about qualified switches, see the Xsan webpage at www.apple.com/xsan/.Fabric configuration You must connect the computers, storage devices, and switches in your Fibre Channel network to form a Fibre Channel fabric. In a fabric, Fibre Channel cables connect node ports (F or N_Port). For more information about setting up your fabric, see the documentation that came with your Fibre Channel switches. Ethernet TCP/IP network Computers on the SAN must be connected to an Ethernet network. Xsan controllers and clients use this network instead of the Fibre Channel network to exchange file system metadata. If the computers on your SAN must communicate with directory servers, a corporate or campus intranet, or the Internet, connect each SAN client and metadata controller to two Ethernet networks: one private subnet for the SAN metadata and a separate connection for directory service, intranet, and Internet traffic. This is especially important if you plan to use the SAN for high-performance applications such as video editing. IP addresses The client and metadata controller computers need static (fixed) IP addresses for Ethernet network connections. For the public intranet and Internet connection, you can enter each computer’s static IP address, subnet mask, router address, and DNS server address manually or configure a DHCP server to provide this information. If you want the DHCP server to provide IP addresses, it must always assign the same static IP address to each SAN computer. Don’t use DHCP to assign dynamic IP addresses to SAN devices. For the SAN metadata network, the SAN computers should have static private (nonroutable) IP addresses (unless you can’t set up a separate, private Ethernet network for SAN metadata). If you’re setting up new computers or computers on which you’ve just installed Mac OS X Lion or Lion Server, you can have Xsan Admin assign and manage addresses for your private metadata network. If you assign addresses yourself, use one of the following ranges of IP addresses on your private (nonrouted) metadata network: Private address range Associated subnet mask Also specified as 10.0.0.0–10.255.255.255 255.0.0.0 10/8 172.16.0.0–172.31.255.255 255.240.0.0 172.16/12 192.168.0.0–192.168.255.255 255.255.0.0 192.168/16 42 Chapter 3 Plan a SANChapter 3 Plan a SAN 43 Directory services If you plan to use user and group privileges to control access to files and folders on the SAN, you should set up or join a central directory of users and groups. A central directory service lets you manage SAN users and groups from one computer instead of having to visit and painstakingly configure each SAN client and metadata controller. If directory service is provided by a Mac Open Directory server, you can have the Xsan setup assistant configure Macs in the SAN to use existing user and group accounts from the Open Directory server. If you have another type of directory service, such as Active Directory, you configure each Mac in the SAN to connect to it for user and group accounts by using the Users & Groups pane of System Preferences (the Accounts pane in Mac OS X or Mac OS X Server v10.6) after initial setup. If your SAN doesn’t have access to an existing directory service, you can specify during initial setup of your Xsan primary metadata controller that you want to use Xsan Admin to manage users and groups. The server setup assistant creates an Open Directory master server on your primary metadata controller. The Xsan setup assistant creates Open Directory replica servers on standby metadata controllers. The Open Directory master provides an LDAP directory, single sign-on user authentication using Kerberos, and password validation using common authentication methods. The replicas improve responsiveness and provide automatic failover of Open Directory services. The Xsan setup assistant also configures Mac clients in the SAN to connect to your Xsan primary metadata controller for Open Directory user and group accounts. If you use network accounts from a Mac server that isn’t an Xsan metadata controller, you don’t use Xsan Admin to manage user and group accounts. If the network accounts server (or directory server) has Mac OS X Lion Server, use the Server app to manage network user and group accounts. If the network account server has Mac OS X Server v10.6 Snow Leopard or earlier, use Workgroup Manager to manage user and group accounts. Note: Some apps running on SAN client computers, such as Final Cut Pro, work better when users have local home folders, not network home folders. User accounts that you manage with Xsan Admin are set up with local home folders. For help setting up local home folders for user accounts that you don’t manage with Xsan Admin, see “Configure local home folders for network accounts” on page 96. If you decide not to use a central directory service, you must set up the same users and groups in the Accounts pane of System Preferences on each SAN computer.Important: If you create users and groups on each SAN computer, be sure that:  Each user or group has a numeric user ID (UID) or group ID (GID) that is unique throughout the SAN  Each user or group defined on more than one computer has the same UID or GID on each computer Outgoing mail service Xsan can send SAN status notifications via email on your local network (IP subnet) without using a separate mail server. However, depending on your network configuration, you may need an SMTP server to send notifications outside your local network. If you don’t have access to an outgoing mail server, use the mail service in Mac OS X Lion Server to set one up. For information, open the Server app and search Server Help. Plan your SAN It’s easy to add storage to an Xsan SAN, but reorganizing a SAN after you set it up isn’t simple. So, it’s important to plan the layout and organization of your SAN and its storage before you set it up. An Xsan SAN is made up of:  Storage devices (RAID systems)  LUNs (SCSI logical unit numbers, usually RAID arrays)  Storage pools (groups of LUNs)  Affinity tags, which identify storage pools with similar performance and data protection  Volumes (groups of storage pools visible to users)  Clients (computers that use volumes)  Controllers (computers that manage volume metadata)  An Ethernet network used to exchange volume metadata  A Fibre Channel network used to transfer data to and from volumes Before you set up a SAN, you must decide how to organize these components. Take the time to create a diagram or a table that organizes available hardware into RAID arrays, volumes, client computers, and metadata controllers in a way that meets SAN users’ needs and your needs as the SAN administrator. You don’t need to plan storage pools or affinity tags if you set up each volume using a preset volume type based on the kind of work the volume supports. 44 Chapter 3 Plan a SANChapter 3 Plan a SAN 45 Preliminary planning questions As you plan, consider the following questions:  How much storage do you need?  How do you want to present available storage to users?  What storage organization makes the most sense for user workflow?  What levels of performance do users require?  How important is high availability?  What are your requirements for security? Your answers to the questions above will help you decide the following:  What RAID schemes should you use for your RAID arrays?  How many SAN volumes do you need?  How should individual volumes be organized?  Which preset volume type can you choose for each volume?  Which LUNs should be assigned to each affinity tag?  Which clients, users, and groups should have access to each volume?  Which computers will act as metadata controllers?  Do you need standby metadata controllers?  Do you need to adjust a volume’s allocation strategy?  How should you configure your Ethernet network? Review the considerations and guidelines on the following pages for help creating a suitable SAN design. Planning considerations and guidelines The following considerations might help improve your SAN design decisions. How much storage? Because it’s easy to add storage for user data to an Xsan SAN, you only need an adequate starting point. You can add storage later as needed. However, you can’t expand a storage pool that can only store volume metadata or journal data, so try to allocate enough space for metadata and journal data right from the start. (You can add an entire storage pool for metadata and another storage pool for journal data.) For help estimating your metadata and journal data storage requirements, see “Estimate metadata and journal data storage needs” on page 51. Note that the number of RAID systems you use affects not only available space but also SAN performance. See “Performance considerations” on page 46.How should users see available storage? If you want users working on a project to see a volume dedicated to their work, create a separate volume for each project. If it’s acceptable for a user to see a folder for his or her work on a volume with other peoples’ folders, create a single volume and organize it into project folders. Workflow considerations How much file sharing is required by your users’ workflow? For example, if different users or groups work on the same files, simultaneously or in sequence, store those files on a single volume to avoid needing to maintain or hand off copies. Xsan uses file locking to manage shared access to a single copy of the files. Performance considerations If your SAN supports an application (such as high resolution video capture and playback) that requires the fastest possible sustained data transfers, design your SAN with these performance considerations in mind:  Set up the LUNs (RAID arrays) using a RAID scheme that offers high performance. See “Choose RAID schemes for LUNs” on page 47.  Assign your fastest LUNs to an affinity tag for the application. Assign slower LUNs to an affinity tag for less demanding applications.  To increase parallelism, spread LUNs across RAID controllers. Xsan then stripes data across the LUNs and benefits from simultaneous transfers through two RAID controllers.  To increase parallelism for an affinity tag assigned to relatively small LUNs (the size of one or a few drive modules), create a slice of similar size across all drives on a RAID controller instead of creating the LUNs from one or two drive modules.  Spread file transfers across as many drives and RAID controllers as possible. Try creating slices across the drives in RAID systems, and then assign these slices to the same affinity tag.  To increase throughput, connect both ports on client Fibre Channel cards to the fabric.  Store file system metadata on a separate storage pool from user data and make sure the metadata LUNs aren’t on the same RAID controller as user data LUNs.  You can use a separate storage pool for journal data when you create a new volume. This significantly improves performance for some operations, such as creating and deleting files.  Use a second Ethernet network (including a second Ethernet port for each SAN computer) for SAN metadata.  If your SAN uses directory services, mail services, or other services on a separate server, connect SAN computers to that server on an Ethernet network separate from the SAN metadata network. 46 Chapter 3 Plan a SANChapter 3 Plan a SAN 47  Choose a different primary metadata controller for each volume, and set up volume failover priorities to minimize the possibility of more than one volume failing over to the same metadata controller.  If all computers on your SAN are Macs, enable Extended Attributes for your volumes to eliminate the overhead of file information being stored in multiple hidden files. Availability considerations If high availability is important for your data, set up at least one standby metadata controller in addition to your primary metadata controller. Also, consider setting up dual Fibre Channel connections between each client, metadata controller, and storage device using redundant Fibre Channel switches. WARNING: Losing a metadata controller without a standby can result in the loss of all data on a volume. A standby controller is strongly recommended. Security considerations If your SAN supports projects that must be secure and isolated from each other, create separate volumes for each project to eliminate any possibility of the wrong client or user accessing files stored on a volume. As the SAN administrator, you control which computers are SAN clients. Users whose computers aren’t SAN clients or controllers can’t browse for or mount SAN volumes. You use Xsan Admin to remove clients from the SAN. However, you can’t control which Xsan 2.3 computers can use a volume. Users whose SAN computers have Mac OS X Lion or Lion Server can mount all SAN volumes themselves. You can also set up access control lists (ACLs) in Xsan Admin or assign user and group permissions to folders using standard file access permissions in the Finder. Choose RAID schemes for LUNs Much of the reliability and recoverability of data on a SAN is provided not by Xsan, but by the RAID arrays you combine to create storage pools and volumes. Before you set up a SAN, use the RAID system configuration or administration software to prepare LUNs based on specific RAID schemes. WARNING: If a LUN in the metadata storage pool fails and can’t be recovered, all data on the volume is lost. It is strongly recommended that you use only redundant LUNs (LUNs based on RAID schemes other than RAID 0) to create Xsan volumes. For information about removing a failed LUN in a user data storage pool, see the AppleCare Support article at support.apple.com/kb/HT4656.LUNs configured as RAID 0 arrays (striping only) or LUNs based on single drives are difficult or impossible to recover if they fail. Unprotected LUNs such as these should be used only in storage pools that store scratch files or other data that you can afford to lose. Most RAID systems support all popular RAID levels. Each RAID scheme offers a different balance of performance, data protection, and storage efficiency, as summarized in the following table. RAID level Storage efficiency Read performance Write performance Data protection RAID 0 Highest Very High Highest No RAID 1 Low High Medium Yes RAID 3 High to very high Medium Medium Yes RAID 5 High to very high High High Yes RAID 0+1 Low High High Yes Decide on the number of volumes A volume is the largest unit of shared storage on the SAN. If users need shared access to files, store those files on the same volume. This makes it unnecessary for them to pass copies of the files among themselves. However, if security is critical, remember you can’t control client access by unmounting volumes on Xsan 2.3 clients. Users whose computers have Mac OS X Lion or Lion Server can mount SAN volumes themselves. For a typical balance of security and shared access, create one volume and control access with folder access privileges or ACLs in Xsan Admin or the Server app. Decide how to organize a volume You can help users organize data on a volume or restrict users to specific areas of the volume by creating predefined folders. You can control access to these folders by assigning access permissions using Xsan Admin. You can assign folders to specific storage pools using affinities. For example, you can create a folder for data that requires fast access and assign that folder to your fastest storage pool. Assign LUNs to affinity tags When you create a volume using a preset volume type that fits your SAN scenario, Xsan Admin sets up storage pools and affinity tags for best performance. All you do is assign LUNs to each affinity tag. Xsan Admin determines the optimal number of storage pools to create, based on the volume type and the number of LUNs you assign to each affinity tag. 48 Chapter 3 Plan a SANChapter 3 Plan a SAN 49 For best performance, assign LUNs in the multiples shown below. These multiples apply to affinity tags used for user data, not to the Metadata and Journal affinity tag, which needs one LUN. Important: Assigning LUNs other than in the multiples shown below can result in serious fragmentation. For this volume type’s affinity tags used for user data Assign LUNs in multiples of General File Server 2 Home Folder Server 2 Mail Cluster 1 Podcast Producer Cluster 4 Standard Definition Video 4 Uncompressed High Definition Video 4 Assign LUNs that have the same capacity and performance characteristics to each affinity tag. LUNs that you assign to an affinity tag should have the same capacity, because Xsan provides high performance by using the RAID 0 scheme to stripe data across the LUNs in each storage pool. This striping scheme can use available space on each LUN equal to the capacity of the smallest LUN in a storage pool. If a storage pool’s LUNs vary in size, this can result in wasted capacity. For example, if a storage pool has a 240 GB RAID array and a 360 GB RAID array, 120 GB of the larger array won’t be used. By assigning LUNs with similar capacities to an affinity tag, you avoid wasting available storage. If you’re using a volume type with multiple affinity tags for user data, assign your fastest LUNs to the affinity tag associated with folders whose contents benefit most from extra performance. Assign slower LUNs to an affinity tag associated with folders whose contents don’t have critical performance requirements. You can also increase the performance of an affinity tag’s storage pools by assigning that affinity tag a combination of LUNs that are hosted on different drive modules and different RAID controllers. This strategy increases performance by increasing the parallelism of data transfers. Decide which clients to mount a volume on If you create multiple volumes, decide which volumes should be mounted on which clients. A new volume is initially mounted on all clients. When you add a client to the SAN, volumes that are currently mounted on all SAN computers will be mounted automatically on the new client. If a volume isn’t mounted on all SAN computers, and you add a new client, the volume isn’t mounted automatically on the new client. If a volume isn’t mounted on all SAN computers but is mounted on all metadata controllers, and you add a metadata controller, the volume is mounted automatically on the new metadata controller. If you stop a volume, it isn’t mounted automatically on any SAN computers when you start the volume again. You can use Xsan Admin to mount or unmount a volume on selected clients. Users whose SAN computers have Mac OS X Lion or Lion Server can mount and unmount SAN volumes themselves using the Xsan pane of System Preferences. Choose metadata controllers You must choose at least one computer to be the SAN metadata controller, the computer that is responsible for managing file system metadata. Note: File system metadata and journal data are stored on the SAN volume, not on the metadata controller itself. For more information, see “Store user data with metadata and journal data” below. If high availability is important, use at least two metadata controllers: one as the primary controller and one as a standby. You can specify additional metadata controllers as needed, and set each volume’s failover priorities to determine the order in which the controllers are tried if a volume’s primary controller stops responding. If performance is critical, don’t run other server services on the metadata controller and don’t use the controller to reshare a SAN volume using AFP or NFS. Choose standby controllers To be sure that SAN volumes are always available, set up at least one standby metadata controller that can take over if your primary metadata controller fails. Store user data with metadata and journal data The metadata and journal data that describe a volume are stored not on the volume’s metadata controller, but on the volume. Metadata is stored on the first storage pool in the volume. Journal data can be stored on any storage pool in the volume. You must have only one storage pool with journal data. Preset volume types set up a separate storage pool used only for metadata and journal data. If you set up a custom volume with more than one storage pool, you can choose whether the metadata and journal storage pool is allowed to store user data. You might get adequate performance by combining metadata and journal data on the same storage pool as user data, but for better performance, use a separate storage pool for metadata and journal data. 50 Chapter 3 Plan a SANChapter 3 Plan a SAN 51 Estimate metadata and journal data storage needs To estimate the amount of space required for Xsan volume metadata, assume that 10 million files on a volume require approximately 10 GB of metadata on the volume’s metadata storage pool. The journal requires between 64 KB and 512 MB. Xsan configures a fixed size when you create a volume. Due to the small size, you can use a single RAID 1 LUN for the journal storage pool. To maximize the performance benefit of a separate journal storage pool, dedicate entire physical disks to the RAID 1 LUN. Choose an allocation strategy If you choose a preset volume type when you set up a volume, Xsan Admin sets its volume allocation strategy for you. Later, you can change the allocation strategy by editing volume settings with Xsan Admin. The allocation strategy you choose for a volume determines the order in which its storage pools are filled with data. You can choose round robin, fill, or balance:  If you choose round robin, Xsan writes data to each storage pool in the volume in turn. This is normally the best choice for performance.  If you choose fill, Xsan writes data to the first storage pool in the volume until that storage pool is full, and then moves to the next storage pool. This is a good choice to keep a specific storage pool unused as long as possible.  If you choose balance, Xsan writes data to the storage pool that has the most free space. Plan the Ethernet TCP/IP network Ethernet connections are used in several ways in an Xsan SAN:  Xsan clients and metadata controllers use Ethernet to exchange volume metadata.  Xsan clients can use Ethernet for access to networks outside the SAN (campus or corporate intranet or the Internet).  Xsan metadata controllers can use Ethernet connections for remote management.  RAID systems can use Ethernet connections for system management.  Fibre Channel switches can use Ethernet connections for switch management. You have two options:  Use one Ethernet network for all traffic. This is the less expensive option, but is also less secure and might not provide the best performance.  Use two separate networks—one for metadata and another for all other IP traffic. This configuration is slightly more expensive (requiring two Ethernet adapters for each computer and an additional switch) but offers greater security and better performance because routine network traffic doesn’t interfere with SAN volume metadata traffic.Use a private metadata network Non–SAN-related Ethernet traffic can interfere with the exchange of metadata among Xsan controllers and clients. For example, using the same connection for Xsan metadata exchange and Internet access can slow file system performance. Similarly, using the same Ethernet network to connect client computers to directory services and SAN metadata can affect SAN performance. If SAN performance is critical for your users or applications, keep all extraneous traffic off the network that clients and metadata controllers use to exchange metadata. For best SAN performance, set up a private Ethernet TCP/IP network for the exclusive use of Xsan clients and metadata controllers. For other types of network traffic, including Internet access, RAID system and Fibre Channel switch management, remote SAN management, or directory services, connect each client and metadata controller to a second Ethernet network using a second Ethernet port. Use switches instead of hubs To get the best performance, use Gigabit Ethernet switches, not hubs, in the SAN metadata network. Plan the Fibre Channel network Xsan uses Fibre Channel connections to:  Transfer user data between clients and data storage pools  Transfer metadata between metadata controllers and metadata storage pools If you have connections operating below the data rate supported by your equipment (typically 2 or 4 Gb/s), verify Fibre Channel performance and troubleshoot the fabric. Verify base Fibre Channel performance Because the devices connected to a Fibre Channel network adjust their speed to match the slowest device on the fabric, be sure that all connections in the fabric are operating at the expected speed (typically 2 or 4 Gb/s). Check Fibre Channel connection performance: m Use the management software provided with your Fibre Channel switches to test the performance of your Fibre Channel fabric. If your Fibre Channel fabric is running slowly If your Fibre Channel fabric isn’t running at the expected speed (typically 2 or 4 Gb/s, depending on your equipment), review the following information. 52 Chapter 3 Plan a SANChapter 3 Plan a SAN 53 Check cables One faulty cable in a fabric can slow the entire network. Check all cables to make sure they’re capable of full transmission speed. Use your switch management software to isolate the faulty cable by checking the performance of specific connections. Use qualified transceivers Check with the manufacturers of the devices you’re connecting to your fabric to be sure that the transceivers (GBICs) you’re using are qualified for use with their devices. With some Fibre Channel switches, you should use identical transceivers (same manufacturer and model number) on both ends of each cable. Mismatched optical transceivers (even if they are separately qualified for use with your devices) can cause Fibre Channel communication errors and degrade SAN performance. With Cisco Fibre Channel switches, you should use a Cisco transceiver on the end of a cable that plugs into the switch, but use another qualified transceiver at the other end of the cable. For Fibre Channel hardware compatibility information, see the AppleCare Support article at support.apple.com/kb/HT1769. Check Fibre Channel switch port configuration The Request for State Change Notifications (RSCN) that is generated when a client on the SAN restarts can cause dropped frames in video streams to other clients. To avoid interrupting SAN traffic to other clients if one client restarts, check your Fibre Channel switch documentation to see if you can configure the switch to suppress RSCNs on initiator ports. (For example, on Qlogic switches this feature is called I/O StreamGuard.) Connect devices to specific blades If your Fibre Channel switch is based on a blade architecture, you might be able to improve performance by:  Connecting pairs of devices that routinely exchange large volumes of data to the same blade in the switch  Distributing loads across multiple blades instead of concentrating all of the load on one or two blades Configure RAID systems Follow these guidelines when you set up your RAID systems for use as Xsan LUNs. Install the latest firmware To get the best performance and reliability from your RAID systems, install the latest firmware.Connect RAID systems to an Ethernet network For best performance, don’t connect RAID controller Ethernet management ports to the SAN’s metadata network. Connect the ports to the separate Ethernet network that you use for other types of network traffic, such as directory services, Internet access, and remote Xsan management. Choose RAID levels for LUNs Use RAID 1 for metadata LUNs and RAID 5 for data LUNs. Use RAID 1 for metadata LUNs RAID 1 (mirroring) can give slightly better performance than the default RAID 5 scheme for the small, two-drive metadata LUNs that Xsan uses to store volume information. A single drive is almost always adequate for storing the primary volume metadata. (10 GB of metadata space is enough for approximately 10 million files.) The second, mirror drive protects you from metadata loss. Use RAID 5 for data LUNs Most RAID systems are optimized for excellent performance and data redundancy using a RAID 5 scheme. (RAID 5 stripes data across available drives and distributes parity data across the drives.) Some RAID systems ship preconfigured as RAID 5 LUNs. RAID 0 (striping with no parity) might give slightly better write performance, but it provides no data recovery protection, so RAID 5 is always a better choice for LUNs used to store user data. Adjust RAID system performance settings RAID system performance settings, which affect parameters such as drive caching, RAID controller caching, and read prefetching, can have a significant effect on Xsan volume performance. Follow these guidelines. Enable drive caching In addition to the caching performed by the RAID controller, each drive in an array can perform caching at the drive level to improve performance. WARNING: If you enable drive caching for a RAID set, make sure the system is connected to an uninterruptible power supply (UPS). Otherwise, you could lose cached data if the power fails. Enable RAID controller write caching Without RAID controller write caching, a request to write data to the associated LUN isn’t considered finished until the data is written to the physical disks that make up the array. Only then can the next write request be processed. (This is sometimes called write-through caching.) 54 Chapter 3 Plan a SANChapter 3 Plan a SAN 55 When RAID controller write caching is enabled, a request to write data is considered finished when the data is in the cache. This is sometimes called write-back caching. Write requests are processed more quickly because the file system only needs to write to the fast cache memory and doesn’t need to wait for the slower disk drives. Be sure to enable write caching on RAID controllers that support metadata storage pools. Although some large write requests might benefit from caching, often they don’t. By placing a volume’s metadata storage pool on a RAID controller separate from the data storage pools, you can enable caching on the RAID controller used for metadata and disable caching on the RAID controller used for data. When the file system is relying on caching in this way, you must guarantee that data in the cache isn’t lost before it’s written to disk. Data written to disk is safe if the power fails, but data in a cache is not. To be sure that a power failure can’t cause the loss of cached data, protect your RAID systems with RAID controller backup batteries or a UPS. WARNING: If you enable controller write caching on a RAID system, make sure the system includes controller backup batteries and, preferably, is connected to a UPS. Enable read prefetching Read prefetching is a technique that improves file system read performance when data is being read sequentially, as in the case of audio or video streaming, for example. When read prefetching is enabled, the RAID controller assumes that a read request for a block of data will be followed by requests for adjacent data blocks. To prepare for these requests, the RAID controller reads the requested data and the following data, and stores it in cache memory. Then, if the data is requested, it’s retrieved from the fast cache instead of from the slower disk drives.56 Follow step by step instructions for setting up a shared volume on an Xsan SAN. This chapter explains how to connect SAN networks, prepare RAID arrays (LUNs), use the Xsan Admin app, set up a SAN, and create a shared volume. This chapter also tells you how to administer Xsan remotely, rename a SAN, remove a SAN, set up additional SANs, and manage multiple SANs. Connect computers and storage devices Before you open Xsan Admin to configure your SAN, you must connect client computers, controller computers, and storage devices to the SAN’s Fibre Channel and Ethernet networks. In addition, make sure your networks meet the requirements summarized in “Fibre Channel fabric” on page 41 and “Ethernet TCP/IP network” on page 42. Prepare LUNs New RAID systems often come configured as one or more RAID arrays. So, out of the box, your RAID system might provide LUNs that you can use for most SAN applications. For details, see the documentation for your RAID system. Unless you have well-defined, special needs, no other LUN preparation is needed. To set up other combinations of RAID arrays or slices, use the management software that comes with your RAID systems to create the arrays before you add the resulting LUNs to your SAN’s storage pools. For information about choosing a RAID scheme, see “Choose RAID schemes for LUNs” on page 47. Note: Don’t use Disk Utility to format arrays or slices for use with Xsan. LUNs are labeled and initialized when you add them to a storage pool using Xsan Admin. After they are labeled, the LUNs can’t be modified using Disk Utility. 4 Set up a SANChapter 4 Set up a SAN 57 Be sure to create arrays of the same size if you plan to add them to the same affinity tag (or the same storage pool of a custom volume). For more information, see “Assign LUNs to affinity tags” on page 48. Use the server setup assistant to configure controllers You use the server setup assistant to configure servers as Xsan metadata controllers. The server setup assistant runs when you start up a new server or a server on which you have performed a clean installation of Mac OS X Lion Server. When using the server setup assistant to set up your primary metadata controller, you can choose how to manage Xsan users and groups. Manage users and groups with Xsan Admin When using the server setup assistant to set up your primary metadata controller, you can choose to manage SAN users and groups with Xsan Admin. This option is recommended if you don’t have a directory server and you expect to have up to 20 SAN users. These users will have local home folders on their computers (not network home folders on the server). Important: You can choose to manage users and groups with Xsan Admin only when you use the server setup assistant to set up your primary metadata controller. You can’t configure this option after setting up the primary controller with the server setup assistant. If you choose this option, the server setup assistant makes the primary metadata controller an Open Directory master server. Then Xsan Admin configures standby metadata controllers as Open Directory replica servers. For the Open Directory master and replicas, the directory administrator’s user name is Directory Administrator, the short name is diradmin, and the password is initially the same as the password of the administrator account that you create with the server setup assistant. Xsan Admin also configures Xsan client computers with Xsan 2 to connect to your Xsan primary metadata controller for Open Directory user and group accounts. Use an existing Open Directory server If you have an Open Directory server, you can have the server setup assistant configure your primary metadata controller to get users and groups from it. Then when you set up your SAN, the Xsan setup assistant configures standby metadata controllers and client computers to connect to the Open Directory server for users and groups.Use another directory server When using the server setup assistant to set up your primary metadata controller, you can also choose to connect to a directory server, including Active Directory or Open Directory, after you finish setup. In this case, you use the Users & Groups pane of System Preferences (the Accounts pane in Mac OS X or Mac OS X Server v10.6) on each metadata controller and client computer to configure a connection to your directory server. Use Xsan Admin You use the Xsan Admin app to set up and manage your SAN. You can use Xsan Admin to manage an Xsan 2.3 SAN from any computer that has Mac OS X Lion Server and has access to the same public intranet as the SAN. Xsan Admin is installed with Mac OS X Lion Server, and is located in the /Applications/Utilities/ folder. Connect through a firewall If there’s a firewall between the SAN and the computer you’re running Xsan Admin on, be sure port 311 in the firewall is open so Xsan Admin can communicate with the SAN computers. Xsan Admin preferences Open Xsan Admin and choose Xsan Admin > Preferences to adjust these settings:  SAN status refresh interval  The amount of log information displayed  The maximum number of users to list when searching Get help Xsan Admin includes onscreen help. Use the Help menu or click the Help button in any Xsan Admin dialog or pane. SAN and volume setup summary To set up a shared volume on a SAN, you’ll perform the following tasks.  Step 1: Set up the Fibre Channel network (page 59)  Step 2: Set up the Ethernet networks (page 59)  Step 3: Configure SAN computers to use a time server (page 60)  Step 4: Set up SAN users and groups (page 61)  Step 5: Set up RAID systems (page 62)  Step 6: Create a metadata array (page 62)  Step 7: Install Xsan software on clients and controllers (page 63)  Step 8: Configure the SAN (page 64) 58 Chapter 4 Set up a SANChapter 4 Set up a SAN 59  Step 9: Create a volume (page 65)  Step 10: (Optional) Set up SAN status notifications (page 68)  Step 11: (Optional) Assign folders to affinity tags (page 68)  Step 12: (Optional) Set user and group quotas (page 68) Set up an Xsan volume on a SAN Step 1: Set up the Fibre Channel network Set up the SAN Fibre Channel network: m Connect controller computers, client computers, and RAID storage systems to a Fibre Channel switch to create a Fibre Channel fabric for the SAN. Be sure to configure the switch and make the connections so you create a Fibre Channel fabric. For more information, see the guidelines and requirements in “Fibre Channel fabric” on page 41. Step 2: Set up the Ethernet networks Set up the SAN Ethernet networks: 1 Connect controller computers, client computers, RAID systems, and Fibre Channel switches to the public intranet and Internet. 2 Connect controller computers and client computers to the private metadata network. 3 Configure the network settings on the client and controller computers. For each computer’s public Ethernet port, you can configure the TCP/IP settings: Manually: You enter the static IP address, subnet mask, router address, and DNS server address for each computer. Using DHCP with manual address: You enter the computer’s static IP address, and your DHCP server provides the other TCP/IP connection settings. Using DHCP: Your DHCP server provides a static IP address and the other TCP/IP settings for client computers. (This configuration method isn’t available when setting up metadata controllers.) The DHCP server must be configured to always assign the same static IP address to each SAN computer.For the private metadata network, you can have the Xsan setup assistant configure the network settings if you’re setting up new computers or computers on which you’ve just performed a clean installation of Mac OS X Lion Server. To make sure the Xsan setup assistant offers this option, don’t configure the Ethernet port connected to the private metadata network:  On client computers, leave this Ethernet port unconfigured in Network preferences.  On controllers and clients with Mac OS X Lion Server, disable this Ethernet port while using the server setup assistant. The Xsan setup assistant offers to configure the private metadata network if it finds exactly one available unconfigured Ethernet port on each computer, or if each computer has an Ethernet port with a private IP address on the same IP subnet and a subnet mask of 255.255.255.0. For information about private IP addresses and the network settings you must make if the Xsan setup assistant doesn’t configure the metadata network settings on SAN computers, see “Ethernet TCP/IP network” on page 42. 4 Make sure all client and controller computers have different computer names, so you can distinguish them in Xsan Admin. Step 3: Configure SAN computers to use a time server To ensure consistent time metadata across all computers in the SAN, choose the same network time server for all metadata controller and client computers in the SAN. Choose a time server: m On each SAN computer, open Date & Time preferences and choose the same network time server for all metadata controller and client computers. If you’re setting up a new server or a computer that you’ve performed a clean installation of Mac OS X Lion Server on, you can choose a network time server in the Time Zone pane of the server setup assistant. 60 Chapter 4 Set up a SANChapter 4 Set up a SAN 61 Step 4: Set up SAN users and groups Here are several ways you can set up users and groups for your SAN: m If you’re setting up a new primary metadata controller or one you’ve just performed a clean installation of Mac OS X Lion Server on, select an option in the “Users and Groups” pane of the server setup assistant. Manage users and groups with Xsan Admin: Select this option to have the server setup assistant create a centralized directory of users and groups on the primary metadata controller. You can select this option only while setting up Mac OS X Lion Server on the primary metadata controller. You can’t configure this option after using the server setup assistant on the primary controller. After setup, you use Xsan Admin to create and delete users and groups and to change group membership. For information about Open Directory servers, see “Directory services” on page 43. Use existing users and groups from an Open Directory server: Select this option to have the server setup assistant configure the primary metadata controller to connect to the Open Directory server whose DNS name or IP address you specify. If you select this option, Xsan Admin configures all other SAN computers with Xsan 2 to use the Open Directory server. You can set up an Open Directory server, also called a network account server, and manage users and groups by using the Server app on a server with Mac OS X Lion Server. Connect to a directory server later: Select this option if you have another type of directory server, such as Active Directory.After setting up the primary metadata controller, use the Users & Groups pane of System Preferences (the Accounts pane on client computers with Mac OS X or Mac OS X Server v10.6) to connect the computer to your directory server. m If you don’t use a directory server, you must create the same set of users and groups in System Preferences on each SAN computer. Important: If you create users and groups on each SAN computer, make sure each user and group has a numeric user ID (UID) or group ID (GID) that is unique throughout the SAN, and make sure each SAN user and group has the same UID or GID on all SAN computers. One way to do this is to create an identical list of users and groups in the same order on each computer, following a clean installation of the operating system. Step 5: Set up RAID systems Set up RAID Systems: 1 Follow the instructions that come with your RAID systems to turn them on and configure their network, management, and security settings. 2 If your RAID systems come with RAID sets already configured, they’re detected during SAN setup and you can skip to “Step 6: Create a metadata array”on page 62; otherwise, use the management software that comes with the RAID system to create arrays based on the RAID schemes of your choice, leaving three drives on one system unassigned so you can create a small, separate metadata LUN as described in the next step. For help choosing other RAID schemes, see “Choose RAID schemes for LUNs” on page 47. Setup scripts for common configurations on Promise RAID systems are available at www.apple.com/support/xsan/. Step 6: Create a metadata array Ten GB of disk space is enough to store the metadata for a volume containing 10 million files, so a two-drive RAID 1 (mirrored) array is generally large enough to store the metadata for your SAN volume. If you dedicate a spare drive to this array to guarantee availability, three drives are adequate for your SAN metadata. If your RAID arrays consist of four or more drives, use these steps to convert an existing array into a small metadata array so you can reuse the extra drives. If you’ve set up a Promise RAID system using a script from www.apple.com/support/xsan/, you should already have a two-drive RAID 1 array for metadata, and you can skip to “Step 7: Enable Xsan on clients and controllers” on page 63. Create the metadata array: 1 If you don’t have three spare drives or if all drives in your RAID systems belong to RAID arrays, use the management app for your RAID system to delete an existing array. 2 Use two of the drives to create a two-drive RAID 1 (mirrored) array. 3 Assign a third drive as a dedicated spare for the array. 62 Chapter 4 Set up a SANChapter 4 Set up a SAN 63 You can use leftover drives from the original array to create a separate array, or save them for use as spares. Step 7: Enable Xsan on clients and controllers Enable Xsan on a computer with Mac OS X Lion or Lion Server: m On each computer that has Mac OS X Lion or Lion Server and is connected to the SAN, open System Preferences, click Xsan, and then click Enable Xsan. Enable Xsan on a computer that has no keyboard or display: 1 Log in to a computer that does have a keyboard and display. 2 In the Finder, choose Go > Connect to Server and enter vnc://address in the Server Address field, replacing address with the IP address or DNS name of the target computer. 3 Click Connect and enter the name and password of an administrator account on the target computer. 4 In the screen sharing window, open System Preferences, click Xsan, and then click Enable Xsan. You can also use the Apple Remote Desktop app (which you can purchase from the Mac App Store) to enable Xsan on remote computers. For information about Apple Remote Desktop, go to www.apple.com/remotedesktop/. Enable Xsan on a computer with Mac OS X or Mac OS X Server v10.6: 1 Insert the Xsan Install Disc, double-click the Install Xsan icon, and then follow the onscreen instructions until you reach the Custom Install pane. 2 In the Custom Install pane, deselect Xsan Admin, click Continue, and follow the remaining onscreen instructions to install only the Xsan file system. From the command line For information about using command-line tools in Terminal to install Xsan on a computer with Mac OS X or Mac OS X Server v10.6, see “Install Xsan from the command line” on page 143.Step 8: Configure the SAN You use Xsan Admin to configure the SAN. Configure the SAN: 1 Open Xsan Admin. You can open Xsan Admin after you finish installing the Xsan software on your primary metadata controller computer. You can also open Xsan Admin on any computer with Mac OS X Lion Server and an intranet or Internet connection to your SAN computers. (You can use Xsan Admin on a computer that isn’t connected to the SAN’s private metadata network or its Fibre Channel network.) 2 In the Introduction pane, click Continue. 3 In the Initial SAN Setup pane, select “Configure new SAN.” For information about connecting to an existing SAN, see “Manage multiple SANs” on page 69. 4 In the SAN Settings pane, enter a name for the SAN and then enter the SAN administrator’s name and email address. 5 In the Add Computers pane, make sure all the computers that you want to include in the SAN are selected. If a computer you want to include isn’t listed, make sure Xsan is enabled in that computer’s Xsan preferences (or you’ve installed Xsan, if the computer has Mac OS X or Mac OS X Server v10.6). Check that the computer is connected to both Ethernet networks—the public intranet and the private metadata network—and check the network settings in the computer’s Network preferences. You can also click Add Remote Computer to add computers manually. 64 Chapter 4 Set up a SANChapter 4 Set up a SAN 65 6 In the Authenticate SAN Computers pane, choose how you’ll provide authentication information for the SAN computers: Use same authentication information for all SAN computers: Select this option to have Xsan Admin authenticate to all computers using the administrator name and password you enter in this pane. Authenticate to SAN computers one by one: Select this option to authenticate to each computer individually. 7 If the Serial Numbers pane appears, enter your Xsan serial numbers for client computer with Mac OS X or Mac OS X Server v10.6. You can click Add Serial Number and enter a number, or drag a text file containing serial numbers to the list. 8 In the Choose Metadata Controllers pane, select your primary and standby controllers and deselect client computers that appear in the list. 9 If the Private Metadata Network pane appears, you can choose to have Xsan Admin manage the private metadata network addresses for all SAN computers. 10 If the SAN Network pane appears, choose your private metadata network from the Metadata Network pop-up menu. The SAN Network pane doesn’t appear if, in the previous step, you chose to have Xsan Admin manage the private metadata network addresses. 11 Review the Summary pane, and if all settings are correct, click Continue. To change a setting, click Go Back until you reach the pane where you can correct the setting. Then click Continue until you return to the Summary pane. Step 9: Create a volume When the Xsan setup assistant finishes basic SAN configuration, it asks if you want to create a volume.Create a volume: 1 In the “Create Volume” pane, select “Create a volume now” and click Continue. If you want to create volumes later, follow the instructions in “Add a volume to a SAN” on page 73. 2 In the “Volume Name and Type” pane, enter a name for the volume and choose a volume type that matches the type of work the volume will support. For the volume name, use only uppercase letters (A–Z), lowercase letters (a–z), numbers (0–9), and underscores ( _ ). Don’t include spaces or hyphens. The maximum length is 70 characters. The volume type you choose determines how the setup assistant configures affinity tags and storage pools on the volume. For information, see “How Xsan storage is organized” on page 34. 3 Optionally, click Advanced Settings and adjust the following volume settings: Block Allocation Size: If you’re not sure what value to use, use the preset size or see “Set the block allocation size” on page 80. Allocation Strategy: Choose how storage for files is allocated among the storage pools that belong to the volume. If you choose Round Robin, each request for space is assigned to the next available storage pool in turn. If you choose Fill, space is allocated on the first storage pool until it’s full, then on the second storage pool, and so on. If you choose Balance, space is allocated on the storage pool with the most free space. For more information, see “Choose an allocation strategy” on page 51. Spotlight: Enable this if you want Macintosh clients to search the contents of the volume using Spotlight. Native Extended Attributes: Select this option if all computers on your Xsan 2.3 SAN are Macs (which must have Xsan 2.2.1 or 2.3 to be on the SAN), and you want to ensure the best possible performance by storing related information for each file inside the file itself instead of in separate hidden files. You can’t deselect this option for a volume that was created with the option selected. Access Control Lists: Leave this selected if you want to use access control lists (ACLs) to control access to files and folders on the volume. Case Insensitivity: Select this if all the computers on your SAN have Mac OS X Lion, and you want this volume to ignore capitalization in filenames. For example, myfile, MyFile, and MYFILE are all the same filename if this option is turned on. This option is on by default if the SAN consists only of Macs with Lion. Windows ID Mapping: If you have Windows clients on your SAN, choose how they map user and group information to the Xsan-compatible user IDs (UIDs) and group IDs (GIDs), which they need so they can access Xsan volumes. For more information, see “Map Windows user and group IDs” on page 100. 66 Chapter 4 Set up a SANChapter 4 Set up a SAN 67 4 In the Configure Volume Affinities pane (or the Configure Volume Storage pane, if you’re configuring a custom volume type), drag LUNs from the left column to the corresponding affinity tag (or custom storage pool) in the right column. a Drag the special metadata LUN you created (in Step 6, “Create a Metadata Array”) to the MetadataAndJournal affinity tag (or custom storage pool). b Drag your other LUNs to the other affinity tags (or storage pools). To avoid wasting storage, all LUNs assigned to an affinity tag (or storage pool) should be the same size. c When you finish, click Continue. For information about the optimal number of LUNs to assign to an affinity tag, see “Assign LUNs to affinity tags” on page 48. 5 Optionally, you can select an affinity tag and click Settings to change the affinity tag name or other settings listed below. If you’re creating a custom volume, you can select it and click Storage Pool Settings to change the storage pool name or other settings listed below. Affinity Tag (or Storage Pool Name): Enter the name for the affinity tag (or custom storage pool). If the OK button is disabled when you finish entering the name, the name is reserved; try another. For more information about reserved names, see “If you can’t add a storage pool” on page 124. Use for: Choose the types of data that can be stored on storage pools that have this affinity tag (or that can be stored on the custom storage pool), following these rules: The first affinity in a volume can allow metadata only, journaling and metadata, or any data (which includes metadata, journaling, and user data). Thus the first affinity must always allow metadata. Other affinities can allow any data, only journaling and metadata, only journaling, only metadata, or only user data. Only one affinity can allow journaling. You can’t change the type of data an affinity stores without recreating the volume. If you allow user data only, you can specify whether to allow only data that has the matching affinity. If the data must have the matching affinity, the tag is called “exclusive,” and data without the affinity isn’t allowed. You can change this setting as needed. However, a volume must contain at least one affinity tag that isn’t exclusive. In other words, the volume must contain at least one affinity tag that accepts user data without an affinity. Stripe Breadth: Specify how much data is written to or read from each LUN in storage pools that have this affinity tag (or each LUN in the custom storage pool) before moving to the next LUN. This value can affect performance. If you’re not sure what value to use, accept the preset value.6 If the Volume Failover Priority pane appears, arrange the list so as few SAN volumes as possible have the same metadata controller first on their failover priority lists, and then click Continue. 7 In the Setup Complete pane, click Continue. Xsan Admin displays a summary of your SAN configuration and the new volume is mounted and ready to use in the Finder on all clients and metadata controllers. For information about creating additional volumes, see “Add a volume to a SAN” on page 73. Step 10: (Optional) Set up SAN status notifications Xsan is initially set to notify the administrator by email when the status of the SAN changes. You can have notifications sent to additional email addresses or textmessaging addresses using an SMTP server, and you can choose conditions that trigger notification to each address. If you don’t want to customize notifications now, you can do it later. For instructions, see “Set up status notifications” on page 119. Step 11: (Optional) Assign folders to affinity tags If you want to force files to be stored in specific storage pools, assign the affinity tag of the pools to a folder. Then, files that users put in the folder are stored only on storage pools that have that affinity tag. For instructions, see “Set up a folder affinity”on page 77. Step 12: (Optional) Set user and group quotas You can set up quotas to control how much space on each SAN volume is used by each user or group. For instructions, see “Set SAN user and group quotas” on page 100. Use an Xsan administrator computer The Xsan Admin app is installed with Mac OS X Lion Server, and you can use Xsan Admin on any computer that has Lion Server to administer an Xsan 2.3 SAN remotely. The administrator computer must be able to connect to all SAN computers via your public intranet or the Internet. The administrator computer doesn’t need to be connected to the SAN’s private metadata network or the SAN’s Fibre Channel network. For information about using Xsan Admin to manage a SAN remotely, see “Manage multiple SANs” on page 69. 68 Chapter 4 Set up a SANChapter 4 Set up a SAN 69 Rename a SAN The SAN name appears in the Overview pane of Xsan Admin. The SAN name is initially set when the SAN is set up. You can change this name using Xsan Admin. Change the name of a SAN: 1 Open Xsan Admin and click Overview. 2 Choose Edit SAN Properties from the Action pop-up menu (gear). 3 Type a name in the SAN Name field and click OK. Set up another SAN You can use Xsan Admin to set up more than one SAN. Add a new SAN: 1 Install the hardware, connect the Ethernet and Fibre Channel networks, set up the client computers, set up standby metadata controllers if you have them, set up the RAID systems, create a metadata array, and set up the primary metadata controller as instructed earlier in this chapter. If you’re setting up a SAN for the first time, see the planning guidelines in Chapter 3,“Plan a SAN,” on page 40 and the instructions at the beginning of this chapter. 2 Open Xsan Admin on the computer that you want to use to set up and manage the new SAN. 3 Choose File > New and follow the instructions in “Step 8: Configure the SAN”on page 64. Manage multiple SANs You can use Xsan Admin to manage more than one Xsan 2 SAN. The computer with Xsan Admin doesn’t need to be connected to the SAN’s private metadata network or its Fibre Channel network, but it must be able to connect to the SAN computers via your public intranet or the Internet. Manage another SAN: 1 Open Xsan Admin and choose File > New. 2 Click Continue in the Introduction pane. 3 Select “Connect to existing SAN,” click Continue, and follow the onscreen instructions.Destroy a SAN Follow these steps to take a SAN out of service and remove its metadata controllers, clients, and volumes. WARNING: Removing a SAN destroys its volumes. Data stored on the volumes is no longer available. Destroying a SAN also removes all Xsan configuration files from all SAN computers. If Xsan Admin is managing users and groups, or the metadata controllers were configured to get user and group accounts from an existing directory server, destroying a SAN destroys any Open Directory replicas on standby metadata controllers and disconnects SAN clients from the directory server. Destroy a SAN: 1 If you want files located on the SAN volumes to be available after you remove the SAN, back up the files. 2 Open Xsan Admin and click Overview. 3 Choose Destroy SAN from the Action pop-up menu (gear). 70 Chapter 4 Set up a SAN71 Use Xsan Admin and related command-line tools to expand, add, modify, check, and repair SAN volumes. This chapter shows how you can expand an existing Xsan volume to provide more free space. It also contains information about volume and storage pool settings, and shows how to check and resolve volume integrity and fragmentation problems. Add storage To increase the storage on your SAN, you can:  Add volumes  Add storage pools to existing volumes  Add LUNs to affinity tags If you add a volume based on a custom volume type, you work directly with storage pools. However, if you add a volume using a built-in Xsan volume type (for example, General File Server or Podcast Producer Cluster), you don’t deal directly with storage pools. Instead, you work with affinity tags that represent storage pools. Xsan Admin organizes available LUNs into storage pools for you, based on the performance requirements of the chosen volume type. Adding a storage pool to a volume increases available storage and also requires Xsan Admin to stop the volume and unmount it. Adding storage pools is a quick way to expand a volume and doesn’t require defragmenting the volume to recover performance. Important: If you add LUNs to an affinity tag, add LUNs only in the recommended multiples. Keep surplus LUNs as extras until you have enough to add them in the recommended multiples for the volume type. Adding LUNs other than in the recommended multiples can result in serious fragmentation. 5 Manage SAN storageIf you're using a custom volume type, you can increase storage by adding volumes or storage pools, but don't add LUNs to an existing storage pool. Adding LUNs to an existing storage pool in a custom volume can result in serious fragmentation. Prepare LUNs Each LUN in an Xsan volume is a RAID array. How you set up your arrays depends on the storage device you use. To create a set of LUNs for your SAN, use the administration software for your RAID system to create, for example, LUNs based on different RAID schemes or LUNs based on array stripes. Setup scripts for creating common LUN configurations on Promise RAID systems are available at www.apple.com/support/. Find the drive modules that belong to a LUN To see which physical drive modules belong to a LUN, you can use Xsan Admin to turn on the drive activity lights on the RAID system that hosts the LUN. Click to turn on drive lights for selected LUN. Find a LUN’s drives: m In Xsan Admin, select LUNs in the SAN Assets list, select a LUN in the list of LUNs, and then click the “Identify LUN Using RAID Lights” button in the lower-right corner of the window. Then, look at your RAID hardware to find the drives with activity lights that are on. 72 Chapter 5 Manage SAN storageChapter 5 Manage SAN storage 73 Add a volume to a SAN A single Xsan SAN can provide access to multiple volumes. Click to add a new volume. Select to view current volumes. Add a volume: 1 In Xsan Admin, select Volumes in the SAN Assets list and click the Add Volume button (+). 2 In the Volume Name and Type pane of the assistant, enter a name for the volume and choose a volume type that matches the kind of work the volume will support. Xsan Admin sets the underlying volume settings accordingly. If you expect the volume to be used by client computers with Quantum’s StorNext File System (Windows, AIX, IRIX, Linux, and Solaris computers), click Advanced Settings, and then turn off the Native Extended Attributes option. Leave this option turned on if all computers on your SAN are Macs. WARNING: To avoid data loss, clients with Quantum’s StorNext File System must not access volumes that use extended attributes.3 In the Configure Volume Affinities pane (Configure Volume Storage, if you chose the custom volume type), drag LUNs to affinity tags (or storage pools). 4 In the Volume Failover Priority pane, drag the controller that you want to host the volume whenever possible to the top of the list, and arrange the other controllers in descending order of preference. For information about advanced settings, see “Change advanced volume settings” on page 79 or “Change storage pool settings” on page 83. When you finish, the volume mounts on all SAN clients. Add a storage pool to a volume You can add free space to a SAN volume by adding a storage pool to the volume. If you’re expanding a volume that’s based on a built-in volume type, you can create a new affinity tag and add LUNs to it. Xsan Admin creates and organizes storage pools within that tag for you. If you add LUNs to an existing affinity tag, Xsan Admin creates storage pools for you. If an existing storage pool has fewer LUNs than recommended for the affinity tag, Xsan Admin fills that storage pool before creating a new one. If you’re expanding a custom volume, you create storage pools directly and add LUNs directly to them. Note: A volume can’t contain more than 512 storage pools. Add a storage pool: 1 If necessary, connect the RAID systems that host the storage pool’s LUNs to the SAN Fibre Channel network and turn on the device. 2 In Xsan Admin, select Volumes in the SAN Assets list. 3 Select the volume in the list and choose Expand Volume from the Action pop-up menu (gear). 4 In the Label LUNs pane of the assistant, choose whether to label unlabeled LUNs individually or sequentially based on a label prefix. If you label LUNs individually, click Edit LUN Label on the next pane and enter a new label. If you use a label prefix, Xsan Admin adds a number to the end of the prefix to create a label for each LUN. For example, if you use the prefix “LUN,” your LUNs are labeled “LUN1,” “LUN2,” and so forth. Already-labeled LUNs aren’t affected. 74 Chapter 5 Manage SAN storageChapter 5 Manage SAN storage 75 5 In the Configure Volume Storage pane, click New Affinity Tag (or New Pool) to add an affinity tag (or storage pool), and then drag LUNs to the new tag (or pool). Important: Add LUNs to a new affinity tag in the recommended multiples. Otherwise, serious volume fragmentation can result. 6 Click Continue to unmount and stop the volume, add the new storage, and remount the expanded volume. From the command line You can also add a storage pool by editing the associated volume configuration file in Terminal. For information, see the cvfs_config man page or “Xsan configuration files” on page 158. You can see the cvfs_config man page by entering this command in Terminal: $ man -M /System/Library/Filesystems/acfs.fs/Contents/man/ 4 cvfs_config Add LUNs to an affinity tag You can increase the size of a SAN volume that’s based on a built-in volume type by adding LUNs (RAID arrays or array slices) to affinity tags. Xsan Admin assigns those LUNs to underlying storage pools for you, creating storage pools as needed, based on the optimal number of LUNs per pool for the volume type (“Assign LUNs to affinity tags” on page 48). Note: A storage pool can’t contain more than 32 LUNs, the total number of LUNs in a volume can’t be greater than 512, and you can’t add LUNs to a storage pool that contains only journal data or metadata.Choose compatible LUNs LUNs you add to an existing storage pool must be at least as large as the LUNs in the pool, but if a new LUN is larger than the other LUNs in the pool, its extra capacity can’t be used. Always try to add LUNs that are identical or similar in performance and capacity to the LUNs already in the storage pool. Mixing LUNs of different sizes or speeds in the same storage pool wastes capacity and can degrade performance. Action menu Add a LUN to an affinity tag: 1 If you haven’t done so, connect the RAID system that hosts the LUN to the SAN Fibre Channel network and turn on the device. 2 In Xsan Admin, select Volumes in the SAN Assets list. 3 Select the volume in the list and choose Expand Volume from the Action pop-up menu (gear). 4 In the Label LUNs pane of the assistant, choose whether you want to label unlabeled LUNs individually, or sequentially based on a label prefix. If you label LUNs individually, click Edit LUN Label on the next pane and enter a new label. If you use a label prefix, Xsan Admin adds a number to the end of the prefix to create a label for each LUN. For example, if you use the prefix “LUN,” your LUNs are labeled “LUN1,” “LUN2,” and so forth. Already-labeled LUNs aren’t affected. If your LUNs are already labeled, they aren’t changed. 76 Chapter 5 Manage SAN storageChapter 5 Manage SAN storage 77 5 In the Configure Volume Storage pane, drag the new LUNs to affinity tags. Important: Add LUNs to affinity tags in the recommended multiples. Don’t add LUNs to existing storage pools in a custom volume. Otherwise, serious volume fragmentation can result. 6 Click Continue to unmount and stop the volume, add the storage, and remount the expanded volume. From the command line You can also add LUNs to an affinity tag by editing the associated volume configuration file and using the cvlabel command-line tool in Terminal. For information, see the cvfs_config and cvlabel man pages or “Xsan configuration files” on page 158 and “Label, list, and unlabel LUNs (cvlabel)” on page 151. You can see the cvfs_config man page by entering this command in Terminal: $ man -M /System/Library/Filesystems/acfs.fs/Contents/man/ 4 cvfs_config Rearrange Fibre Channel connections If you need to rearrange Fibre Channel connections when adding LUNs to your SAN, unmount SAN volumes from clients before you disconnect Fibre Channel cables or turn off Fibre Channel switches. Otherwise, if you unplug or interrupt a Fibre Channel connection between a client and a mounted volume, you might cause problems with client apps, making the volume difficult to remount. Set up a folder affinity Every storage pool in a volume has an affinity tag. You can use the tag to be sure that files in a folder are stored on a specific storage pool. Files in folders without affinities are stored on the next available storage pool according to the volume’s allocation strategy (fill, round-robin, or balance). For more information, see “Affinities and affinity tags” on page 35 and “Folders with affinities” on page 36. Some storage pools might be larger, faster, or better protected than others. Using affinities, you can make sure that an app or task that needs speed or extra protection stores its files on a suitable storage pool.Using Xsan Admin, you can choose an affinity for an existing folder or create a folder with an affinity. Action pop-up menu Assign an affinity tag to a folder: 1 In Xsan Admin, select File Management in the SAN Assets list. 2 Select the folder in the columns that list the volume’s contents, choose Set Affinity from the Action pop-up menu (gear), and choose an affinity tag. If the folder doesn’t exist, choose New Folder from the Action pop-up menu (gear), enter a folder name, and then choose an affinity tag. From the command line You can also create a folder and assign it an affinity using the cvmkdir command-line tool in Terminal. For information, see the cvmkdir man page. Change a folder’s affinity You can use Xsan Admin to change a folder’s affinity so all new files placed in the folder are stored on a new storage pool. Change a folder affinity: 1 In Xsan Admin, select File Management in the SAN Assets list. 2 Select the folder, choose Set Affinity from the Action pop-up menu (gear), and then choose the new affinity tag. 3 Click OK. 78 Chapter 5 Manage SAN storageChapter 5 Manage SAN storage 79 Files in the folder aren’t moved to the new storage pool. To move the files that were in the folder to a storage pool with the new affinity tag, use the snfsdefrag commandline tool in Terminal. For information and an example, see the snfsdefrag man page. Remove an affinity You can undo a folder’s affinity for a storage pool by choosing None for the folder affinity. Remove the affinity from a folder: 1 In Xsan Admin, select File Management in the SAN Assets list. 2 Select the folder, choose Set Affinity from the Action pop-up menu (gear), and then choose None for the affinity. Change advanced volume settings If your SAN volume has special configuration requirements, you can change the standard volume settings when you create a volume. You can also change these settings for an existing volume, except for the block allocation size and disabling the extended attributes option. (Once enabled, extended attributes can’t be disabled.) Note: To change a volume’s block allocation size or disable extended attributes, you must destroy and recreate the volume.View or change volume settings: m Select Volume in the SAN Assets list, select the volume in the list, and choose Edit Volume Settings from the Action pop-up menu (gear). The following sections contain information about each setting. Set the block allocation size Xsan uses the volume block allocation size with the storage pool stripe breadth to decide how to write data to a volume. If you create a volume based on a built-in volume type (for example, General File Server or Podcast Producer Cluster), Xsan Admin sets optimal values for you. For most volumes, the preset block allocation size and storage pool stripe breadth result in good performance. However, in some cases you might be able to improve read or write performance by adjusting these settings to suit a specific app. For example, if your app reads and writes small blocks of data, you might improve performance by choosing a correspondingly small block allocation size. Set a volume’s block allocation size: m The block allocation size must be set when the volume is created, and can’t be changed for an existing volume. To set the block allocation size, click the Advanced Settings button on the Volume Name and Type pane when you first add the volume. Change the volume allocation strategy You can change the allocation strategy for a volume, to choose how storage for new files or additional storage for existing files is allocated on the storage pools that belong to the volume. Change the allocation strategy: 1 In Xsan Admin, select Volumes in the SAN Assets list. 2 Select the volume in the list and choose Edit Volume Settings from the Action pop-up menu (gear). 3 Choose an allocation strategy from the pop-up menu: Round Robin: Each request for space is assigned to the next available storage pool in the volume. Fill: All data is stored on the first storage pool until it’s full, then on the next storage pool, and so on. Balance: New data is written to the storage pool that has the most free space. 4 Click OK. Note: After you click OK, the volume restarts. 80 Chapter 5 Manage SAN storageChapter 5 Manage SAN storage 81 Enable or disable Spotlight on a volume You can use Xsan Admin to control whether a volume is indexed and searchable using Spotlight. Enable or disable Spotlight on a volume: 1 In Xsan Admin, select Volumes in the SAN Assets list. 2 Select the volume and choose Edit Volume Settings from the Action pop-up menu (gear). 3 Select or deselect the checkbox next to Spotlight and click OK. Note: After you click OK, the volume restarts. Enable extended attributes If extended attributes were disabled on a SAN volume when it was created, and all computers that use the volume are Macs, you can enable extended attributes for the files on the volume. When extended attributes are enabled, attributes associated with a file are stored inside the file itself, rather than in separate hidden files. Enabling extended attributes improves file system performance. Extended attributes are enabled when you create a volume with Xsan 2.3, unless you deliberately disable them. Important: You can’t disable extended attributes. Enabling them on a volume is a oneway process that can’t be undone. WARNING: To avoid data loss, clients with Quantum’s StorNext File System (Windows, AIX, IRIX, Linux, and Solaris computers) must not access volumes that use extended attributes. Macs clients of an Xsan 2.3 SAN must have Xsan 2.2 or later, which supports extended attributes. Enable extended attributes: 1 In Xsan Admin, select Volumes in the SAN Assets list. 2 Select the volume and choose Edit Volume Settings from the Action pop-up menu (gear). 3 Select the checkbox next to Extended Attributes and click OK. Note: After you click OK, the volume is unmounted from all SAN computers, and then remounted. The time needed to convert the volume to use extended attributes depends on the size of the volume and the number of files stored on it.Enable or disable access control lists You can use Xsan Admin to specify whether the Xsan file system uses access control lists (ACLs) on a volume. Xsan 2 clients and Windows StorNext clients recognize ACLs. UNIX clients ignore ACLs on Xsan volumes. If you have a mix of Windows clients and Xsan clients, they must all be bound to the same directory domain, whether provided by Open Directory configured as a primary domain controller (PDC) or by Windows Active Directory. Note: If you enable ACLs but your SAN includes clients that don’t support them, don’t use those clients to change file or folder ownership information, or inconsistencies might result. Enable or disable ACLs: 1 In Xsan Admin, select Volumes in the SAN Assets list. 2 Select the volume and choose Edit Volume Settings from the Action pop-up menu (gear). 3 Select or deselect the checkbox next to Access Control Lists and click OK. Note: After you click OK, the volume is unmounted from all SAN computers, and then remounted. Change filename case sensitivity If all the computers on your SAN have Mac OS X Lion or Lion Server, you can specify whether a volume ignores capitalization in filenames. For example, a volume can consider myfile, MyFile, and MYFILE to be the same or different filenames. This option is on by default if the SAN consists only of Macs with Lion. For best performance with volumes that you share using the SMB protocol, make them case insensitive. Change filename case sensitivity for a volume 1 In Xsan Admin, select Volumes in the SAN Assets list. 2 Select the volume and choose Edit Volume Settings from the Action pop-up menu (gear). 3 Select or deselect the checkbox next to Case Insensitivity and click OK. When you change case sensitivity, Xsan checks all existing filenames to make sure the change won’t result in filenames being considered the same. This check can take a while. If Case Insensitivity is selected, the volume considers filenames to be the same if they’re spelled alike but capitalized differently. If Case Insensitivity is not selected, the volume considers filenames to be different if they’re spelled alike but capitalized differently. Note: After you click OK, the volume is unmounted from all Xsan computers, and then remounted.. 82 Chapter 5 Manage SAN storageChapter 5 Manage SAN storage 83 Change the Windows ID mapping If you have Windows clients on your SAN, the Windows ID Mapping setting determines how they map user and group information to the Xsan-compatible user IDs and group IDs they need in order to access this volume. For more information, see “Map Windows user and group IDs” on page 100. Change advanced allocation and cache settings Volume settings that control the allocation of space for growing files and the caching of file-related data structures are set by Xsan Admin to suit the type of volume you set up. If necessary, you can use Xsan Admin to adjust these advanced allocation and caching settings for a volume. Important: Do not adjust these settings unless you understand their role in volume performance or you are directed to change them by Apple support personnel. Change advanced volume settings: m In Xsan Admin, select Volumes in the SAN Assets list, select the volume, choose Edit Volume Settings from the Action pop-up menu (gear), and then specify: File Expansion Min: The number of storage blocks added to the file for the first expansion request. File Expansion Increment: The number of storage blocks by which the expansion request is increased for each subsequent request. File Expansion Max: The maximum expansion request that’s allowed. Inode Cache Size: The maximum number of inode data structures that can be cached on the volume by the metadata controller. Buffer Cache Size: The amount of memory that the metadata controller can allocate for storing a volume’s metadata. Note: Changing advanced volume settings causes the volume to restart. Change storage pool settings The SAN Setup assistant chooses storage pool settings based on the type of volume you use them on. To specify storage pool settings yourself, choose an affinity tag or storage pool in the Configure Volume Affinities pane of the SAN Setup assistant when you create a volume, or when you add a storage pool to a volume, and click the Settings button below the list. The best way to set up a SAN is to plan its organization carefully before you set it up, including settings for the storage pools that make up its volumes. To change storage pool settings for an existing volume, you must destroy and recreate the volume.Change the exclusivity of an affinity tag The “Use for” affinity tag setting specifies the type of data—metadata, journaling, or user data—a storage pool with that affinity can store. You choose the type of data when you create a volume, and you can’t change the type of data an affinity stores without recreating the volume. If an affinity allows user data only, you can specify whether to allow only data that has the matching affinity. If the data must have the matching affinity, the tag is called “exclusive,” and data without the affinity isn’t allowed. You can change this setting as needed. Change the exclusivity of an affinity tag: 1 In Xsan Admin, select the storage pool in the Volumes pane and choose Edit Affinity Settings from the Action pop-up menu (gear). 2 Click the checkbox to select or deselect “Only data with affinity.” If the checkbox is deselected, this is the last affinity tag in the volume that isn’t exclusive. A volume must contain at least one affinity tag that isn’t exclusive. In other words, the volume must contain at least one affinity tag that accepts user data without an affinity. Set the storage pool stripe breadth Xsan uses both the storage pool stripe breadth and the volume block allocation size to decide how to write data to a volume. For most SANs, the default values for storage pool stripe breadth and volume block allocation size result in good performance. However, in some cases you might be able to improve read and write performance by adjusting these values to suit a specific application. The stripe breadth must be set when the volume is created; it can’t be changed for an existing volume. Set a storage pool’s stripe breadth: m When you create the volume, click the Settings button below the Affinity Tag list in the Configure Volume Affinities pane of the setup assistant. Maintain SAN volumes Here are several volume maintenance tasks you can perform:  Rename a volume  See whether files or free space have become fragmented, and fix fragmentation.  If users have trouble accessing files, check the integrity of the volume, its metadata, and its files, and make necessary repairs  Destroy a volume so you can use its LUNs in a different volume 84 Chapter 5 Manage SAN storageChapter 5 Manage SAN storage 85 Rename a volume You can use Xsan Admin to change the name of a volume. You can’t rename an Xsan volume using the Finder. Important: During renaming, the volume is unmounted and restarted, and therefore unavailable to clients. Rename a volume: m In Xsan Admin, select Volumes in the SAN Assets list, select the volume, and then choose Rename Volume from the Action pop-up menu (gear). Check volume fragmentation When you create a file, Xsan divides the file into pieces and distributes these pieces efficiently over the LUNs that make up one of the volume’s storage pools. Over time, as the file is modified, its pieces become fragmented in less efficient arrangements. You can use the snsfdefrag command-line tool to check the amount of file fragmentation, or use the cvfsck command-line tool to check the amount of free space fragmentation. Check volume fragmentation: 1 Open Terminal (in the /Applications/Utilities/ folder) on any SAN computer. If you aren’t working at a SAN computer, use SSH to log in to a SAN computer remotely: $ ssh user@computer Replace user with the name of an administrator user on the SAN computer and computer with the SAN computer’s name or IP address. If you have trouble making an SSH connection, check the Sharing pane of System Preferences on the SAN computer to make sure Remote Login service is turned on. 2 To check file fragmentation on a volume, run the snsfdefrag command-line tool with the -cr options: $ sudo snfsdefrag -cr volume 3 To check free space fragmentation on a volume, you must use Terminal on a metadata controller or use SSH to log in to a controller remotely, and run the cvfsck commandline tool with the -f option: $ sudo cvfsck -f volume For more information, see the cvfsck or snsfdefrag man page. Defragment a volume Defragmenting a file reassembles its pieces into the most efficient arrangement. You can use the snfsdefrag command-line tool to defragment a file, a folder, or an entire volume.Defragment a file, folder, or volume: 1 Open Terminal (in the /Applications/Utilities/ folder) on any SAN computer. If you aren’t working at a SAN computer, use SSH to log in to a SAN computer remotely: $ ssh user@computer Replace user with the name of an administrator user on the SAN computer and computer with the SAN computer’s name or IP address. If you have trouble making an SSH connection, check the Sharing pane of System Preferences on the SAN computer to make sure Remote Login service is turned on. 2 Run the snfsdefrag command-line tool. To defragment individual files: $ sudo snfsdefrag -v filename [filename ... ] To defragment a folder: $ sudo snfsdefrag -vr folder To defragment a volume, set folder to the volume name. For more information, see the snfsdefrag man page or “Defragment a file, folder, or volume (snfsdefrag)” on page 154. Check the integrity of a volume If SAN users have trouble accessing files, use the cvfsck command-line tool to check the integrity of a volume, its metadata, and its files. Check a volume: 1 Open Terminal (in the /Applications/Utilities/ folder). 2 If you aren’t working at the SAN controller computer, use SSH to log in to the controller remotely: $ ssh user@computer Replace user with the name of an administrator user on the controller computer and computer with the controller’s name or IP address. If you have trouble making an SSH connection, check the Sharing pane of System Preferences on the controller to make sure Remote Login service is turned on. 3 Run the cvfsck command-line tool (in /System/Library/Filesystems/acfs.fs/Contents/ bin/) to check the volume without making repairs: $ sudo cvfsck -vn volume You’ll see a warning that the journal is active; this is normal. For more information, see the cvfsck man page. 86 Chapter 5 Manage SAN storageChapter 5 Manage SAN storage 87 Repair a volume If the cvfsck tool reveals problems with a volume, you can use the cvfsck commandline tool to repair the volume. Repair a volume: 1 Stop the volume. Open Xsan Admin, select the volume, and click Stop Volume in the Action pop-up menu (gear). The volume will be unmounted on all SAN computers. 2 Open Terminal (in the /Applications/Utilities/ folder). If you aren’t working at the SAN controller computer, use SSH to log in to the controller remotely: $ ssh user@computer Replace user with the name of an administrator user on the controller computer and computer with the controller’s name or IP address. If you have trouble making an SSH connection, check the Sharing pane of System Preferences on the controller to make sure Remote Login service is turned on. 3 Run the cvfsck command-line tool (in /System/Library/Filesystems/acfs.fs/Contents/ bin/) to replay the events that are recorded in the file system journal: $ sudo cvfsck -j volume 4 Check the volume to see if repairs are required: $ sudo cvfsck -vn volume 5 If the report generated in the previous step lists problems, enter the following command to perform a full check and repair of the volume: $ sudo cvfsck -vw volume 6 Start the volume, and then remount it on SAN computers. In Xsan admin, select the volume, and click Start Volume in the Action pop-up menu. For additional instructions, see “Mount a volume on a client” on page 92. For more information, see the cvfsck man page.Check RAID devices If a RAID array that belongs to an Xsan volume becomes damaged and unrecoverable due to a failed disk drive or other hardware failure, the data on the volume can be lost. To avoid this possibility:  Regularly check the state of your RAID hardware, either by using the management app that came with the RAID system or by visiting the hardware to check the state of the status lights. You might be able to set up your RAID system management app to notify you when an array is degraded.  If an array becomes degraded, replace the failed drive immediately to avoid the possibility of an additional drive failure causing the loss of the entire array. To have this happen automatically, set up your arrays with hot spare drives. Destroy a volume You can destroy a volume so you can reuse its LUNs to create new volumes. WARNING: After destroying a volume, data stored on it is no longer available. Destroy a volume: m In Xsan Admin, select Volumes in the SAN Assets list, select the volume in the list, and choose Destroy Volume from the Action pop-up menu (gear). 88 Chapter 5 Manage SAN storage89 You can use Xsan Admin and related command-line tools to add, control, and remove client computers and their users. Xsan clients are computers that have Fibre Channel connections to a SAN. SAN users log in to client computers to access files stored on SAN volumes. This chapter shows you how to add clients, control client access to volumes, and manage user quotas. Add a client Before a computer can use a SAN volume, you must add the computer to the SAN as a client. These instructions show you how to add a client computer to a SAN. Add button Select to view computers already in SAN. 6 Manage clients and usersAdd a client computer to a SAN: 1 Connect the client to the SAN’s Fibre Channel and Ethernet networks. 2 On a client that has Mac OS X Lion or Mac OS X Lion Server, open System Preferences, click Xsan, and then click Enable Xsan. The client can now use Xsan volumes. 3 On a client with Mac OS X or Mac OS X Server v10.6 Snow Leopard, install the Xsan software, and then use Software Update to get the latest Xsan 2.2 update. 4 Open Xsan Admin, select Computers in the SAN Assets list, and then click the Add button (+). 5 In the Add Computers pane of the assistant, make sure there’s a check next to the new client in the list, and then click Continue. If the client isn’t in the list, click Add Remote Computer and add it. 6 In the Authenticate Clients pane, enter the administrator name and password for the client and click Continue. 7 If you’re adding a client with Mac OS X or Mac OS X Server v10.6, and serial numbers aren’t available, the Serial Numbers pane appears so you can add one. 8 In the Choose Metadata Controllers pane, make sure there’s no check next to the new client in the list, then click Continue. 9 In the Summary pane, click Continue. If Xsan Admin won’t add a client that has Mac OS X v10.6 Snow Leopard and Xsan 2.2.1, there may be existing volumes that are case sensitive. Xsan 2.2.1 doesn’t support casesensitive volumes. After you add a client computer to the SAN, volumes that are mounted on all other SAN computers are mounted automatically on the new client. Volumes that are mounted only on some SAN computers aren’t mounted automatically on the new client, but you can mount those volumes manually. For instructions, see “Mount a volume on a client” on page 92. 90 Chapter 6 Manage clients and usersChapter 6 Manage clients and users 91 Add an Xsan serial number If you want to add Xsan software serial numbers for client computers with Mac OS X or Mac OS X Server v10.6 Snow Leopard, you can enter the numbers in Xsan Admin. Add button Select to view current serial numbers. Add an Xsan serial number: 1 In Xsan Admin, select Serial Numbers in the SAN Assets list. If you don’t see Serial Numbers in the SAN Assets list, add a computer that has Mac OS X or Mac OS X Server v10.6 to the SAN. 2 Click the Add button (+). 3 Enter the serial number, registered owner, and organization information provided by Apple, and then click OK. If you have serial numbers in a text file, you can drag the file to the Serial Number list in Xsan Admin. Move a client to a different SAN You can move a client from one Xsan SAN to a different SAN on the same Ethernet subnet and Fibre Channel network. Move a client computer to a different SAN: 1 In Xsan Admin, select Computers in the SAN Assets list. 2 Select the computer in the list and choose “Remove computer from SAN” from the Action pop-up menu (gear)pop-up menu.3 In Xsan Admin, open the window for the SAN you want to move the computer to. 4 In the new SAN window, select Computers in the SAN Assets list and click the Add button (+). 5 Make sure there’s a check next to the computer in the list, and then click Continue. 6 In the Authenticate Clients pane, enter the administrator name and password for the client and click Continue. Mount a volume on a client When you create a volume, it is mounted on SAN computers. However, if you stop a volume or explicitly unmount a volume from a client, you must mount it again to restore access. Select to view computers that don’t have the volume mounted. Select the volume. Mount Read & Write button Mount an Xsan volume on a client: 1 In Xsan Admin, select Mounts in the SAN Assets list. 2 Select the client in the list. 3 Select the volume in the Volume pop-up menu. 4 To allow the client to modify files on the volume, click the Mount Read & Write button. 92 Chapter 6 Manage clients and usersChapter 6 Manage clients and users 93 A volume remains mounted on a client even if the user logs out or the client computer restarts. If you unmount a volume using Xsan Admin, or if the client computer has Mac OS X Lion and the user unmounts the volume using Xsan preferences, the volume remains unmounted after logout and restart. If a user unmounts the volume in the Finder, it remounts in a few moments. From the command line You can also mount a volume on a client using the xsanctl command-line tool in Terminal. For information, see the xsanctl man page or “Mount an Xsan volume” on page 157. Change mount options You can use Xsan Admin to adjust settings that can affect volume access performance. Change mount options: 1 In Xsan Admin, select Mounts in the SAN Assets list. 2 Select the volume in the Volume pop-up menu. 3 Select the client in the list. 4 Choose Edit Mount Options from the Action pop-up menu (gear) and change: Directory cache size: Controls the number of file system directory entries cached on the client for each SAN volume. Increase this value if the volume contains a large number of small files (for example, if the volume hosts a home directory server or mail server). Client worker threads: Controls the number of threads used to communicate with the volume. You might increase this if you’re mounting many volumes on a client. Delay access time updates until files are closed: Lets you increase performance by reducing the number of access time updates on a file that’s read frequently (for example, streaming video). If not enabled, file access time is updated every time the file is read. For more information, see the descriptions of these parameters in the mount_acfs man page. Manage users and groups Depending on how you first set up your SAN, you manage users and groups using Xsan Admin or another app.Manage users and groups with Xsan Admin When you first set up your SAN controllers, you can use Xsan Admin to manage SAN user and group accounts. An Open Directory master is created on your primary metadata controller, with replicas on your standby controllers. You can then use Xsan Admin to create or remove user and group accounts. Manage users and groups with another app If you choose not to manage accounts using Xsan Admin because you already have a network account server, also called a directory server, use the appropriate directory management tool to add or delete accounts. If a Mac with Mac OS X Lion Server is your network accounts server, you can use the Server app to manage user and group accounts. If your network accounts server has Mac OS X Server v10.6 Snow Leopard or earlier, you can use Workgroup Manager to manage user and group accounts. In either case, users can connect their Macs to the network accounts server in the Users & Groups pane of System Preferences (the Accounts pane in Mac OS X v10.6). Add SAN users Only users in the SAN’s directory can log in to a client computer and access Xsan volumes. You can use Xsan Admin to add users to the directory on your primary metadata controller. Select to view current SAN users. Add button 94 Chapter 6 Manage clients and usersChapter 6 Manage clients and users 95 Note: These instructions apply only if, during initial SAN setup, you chose to use Xsan Admin to manage users and groups. If you have a different directory configuration, use the management software for your directory to add user accounts. Add a user: 1 In Xsan Admin, select Users and Groups in the SAN Assets list. Users and Groups appear only if you chose to have Xsan manage users and groups during initial setup. 2 Click the Users button above the list of users and groups. 3 Click the Add button (+). 4 Enter a user name and password, and click OK. Delete SAN users Only users in the SAN’s directory can log in to a client computer and access Xsan volumes. You can use Xsan Admin to delete users from your SAN directory. Note: These instructions apply only if, during initial SAN setup, you chose to use Xsan Admin to manage users and groups. If you have a different directory configuration, use the management software for your directory to delete user accounts. Delete a user: 1 In Xsan Admin, select Users and Groups in the SAN Assets list. 2 Select the user in the list and choose Delete User or Group from the Action pop-up menu (gear). Create groups You can create groups of users to simplify user management. If you chose to have Xsan manage your users and groups, you already have a group named Workgroup that contains all users. Note: These instructions apply only if, during initial SAN setup, you chose to use Xsan Admin to manage users and groups. If you have a different directory configuration, use the management software for your directory to add groups. Add a group: 1 In Xsan Admin, select Users and Groups in the SAN Assets list. 2 Click the Groups filter button above the list of users and groups. 3 Click the Add button (+). 4 Enter a group name and password. 5 Select the checkbox next to the users who belong to the group. 6 Click OK.Delete groups You can use Xsan Admin to delete a group. Note: These instructions apply only if, during initial SAN setup, you chose to use Xsan Admin to manage users and groups. If you have a different directory configuration, use the management software for your directory to delete groups. Delete a group: 1 In Xsan Admin, select Users and Groups in the SAN Assets list. 2 Select the group in the list and choose Delete User or Group from the Action pop-up menu (gear). Change group membership You can use Xsan Admin to change the members of a group at any time. Note: These instructions apply only if, during initial SAN setup, you chose to use Xsan Admin to manage users and groups. If you have a different directory configuration, use the management software for your directory to modify group membership. Change a group’s membership: 1 In Xsan Admin, select Users and Groups in the SAN Assets list. 2 Select the group in the list and click the Edit button in the lower-right corner of the window. 3 Select the checkbox next to a user to add the user to the group, or deselect the checkbox to remove the user. 4 Click OK. Configure local home folders for network accounts Using a network account server (or directory server) simplifies the job of managing user accounts for client computers attached to the SAN. However, some apps, such as Final Cut Pro, work best when a user’s home folder is on the client computer. User accounts that you manage with Xsan Admin are set up with local home folders. If your SAN users have accounts on another directory server and they have network home folders, you can set up local home folders for them. Configure a local home folder with Server If a Mac with Mac OS X Lion Server provides your SAN’s user accounts, you can use the Server app to configure a local home folder for a network user. 1 Open the Server app and connect to the Mac that has Lion Server and provides your SAN’s network accounts. 2 Select Users in the Server sidebar, select the user whose home folder you want to create, and choose Edit User from the Action pop-up menu (gear). 96 Chapter 6 Manage clients and usersChapter 6 Manage clients and users 97 3 Choose Local Only from the Home Folder pop-up menu. If you don’t see a Home Folder pop-up menu above the Groups field, all users have local home folders. The Home Folder pop-up menu isn’t shown unless the network account server is configured to provide network home folders. Configure a local home folder with Workgroup Manager: 1 Open Workgroup Manager and authenticate to your SAN’s Open Directory master. If the computer you’re using has Mac OS X Lion Server but doesn’t have Workgroup Manager, you can install it. Workgroup Manager is available for Lion Server as part of the Server Admin Tools, which you can download from the AppleCare Support Downloads website at www.apple.com/support/downloads/. 2 Click the Users tab, select a user, and click Home. 3 If /Users appears in the list of home locations, select it and click Save. If /Users isn’t in the list, click the Add button (+), and then enter the following in the Full Path field (replacing shortname with the user’s short name): /Users/shortname Leave all other fields blank, click OK, and then click Save. The user’s home folder is created on the client the first time the user logs in. Control client and user access To control access to information on SAN volumes, you can:  Use the Finder’s Get Info window to apply basic access controls to a file or folder.  Use Xsan Admin or the Server app to apply a full set of access control list restrictions.  Use Xsan Admin to unmount a SAN volume from selected client computers (volume-level control).  Remove a client from a SAN (SAN-level control). Control file and folder access using the Finder To restrict access to a file or folder on an Xsan volume, you can use the Get Info window in the Finder. Assign permissions using the Finder: m In a Finder window, select the file or folder, choose File > Get Info, and look under Sharing & Permissions. Control file and folder access using Xsan Admin To restrict user access to specific items on a SAN volume, you can use Xsan Admin to adjust permissions using standard POSIX permissions and access control lists (ACLs).Assign permissions using Xsan Admin: 1 Make sure ACLs are enabled on the volume. For help, see “Enable or disable access control lists” on page 82. 2 In Xsan Admin, select File Management in the SAN Assets list. 3 Select the file or folder you want to protect, and choose Set Permissions from the Action pop-up menu (gear). For more information about file and folder permissions, open the Server app on a SAN computer that has Mac OS X Lion Server, or a SAN computer that has Mac OS X Lion and has the Server app installed for remote server administration, and then search Server Help. Unmount a volume on a client You can unmount a volume from a client computer. A user whose client computer has Mac OS X Lion can also unmount a SAN volume by using the Xsan pane of System Preferences, provided the user knows an administrator name and password for the client computer. A user can also unmount a SAN volume from a client computer temporarily by ejecting it in the Finder, but the volume remounts after a few moments. Select to view computers that have the volume mounted. Select the volume. Unmount button Unmount a volume: 1 In Xsan Admin, select Mounts in the SAN Assets list. 2 Choose the volume from the Volume pop-up menu. 3 Select the client in the list and click the Unmount button. 98 Chapter 6 Manage clients and usersChapter 6 Manage clients and users 99 To select more than one client, hold down the Command or Shift key as you select clients in the list. Remove a client from a SAN You can remove a client computer from a SAN to prevent it from accessing SAN volumes. Select to view computers already in the SAN. Action menu Remove a client from a SAN: 1 In Xsan Admin, select Computers in the SAN Assets list, select the client, and choose “Remove computer from SAN” from the Action pop-up menu (gear). If SAN volumes are mounted on the client, Xsan Admin unmounts them. If you can’t choose “Remove computer from SAN,” make sure all Xsan clients and metadata controllers are turned on and their status is Ready in Xsan Admin’s Computers list. 2 To prevent the client from appearing in the Xsan Admin’s list of computers that can be added to the SAN, do one of the following:  If the client computer has Mac OS X Lion or Lion Server, open System Preferences on the client, click Xsan, and then click Disable Xsan.  If the client computer has Mac OS X or Mac OS X Server v10.6 Snow Leopard, remove the Xsan software by inserting the Xsan Install Disc for Xsan 2.2 in the client computer, opening the Other Installs folder, and double-clicking Uninstall Xsan.mpkg.3 To prevent any possible connection to the SAN, physically disconnect the client computer from the SAN’s Ethernet and Fibre Channel networks. Map Windows user and group IDs You can use the Windows ID Mapping setting for a volume to specify how Windows clients map user and group information to Xsan-compatible user IDs (UIDs) and group IDs (GIDs), which they need in order to access Xsan volumes. Note: To use ID mapping, Windows clients must be running StorNext 2.7. Windows clients can use these methods to provide UIDs and GIDs: Generate IDs from GUID: Windows clients dynamically generate UIDs and GIDs based on Globally Unique Identifier (GUID) information in an Active Directory domain. Choose this method if Macs on the SAN are connected (bound) to Active Directory with the default binding options, which automatically generate IDs. Use IDs from LDAP (RFC 2307): Windows clients get UID and GID values from the uidNumber and gidNumber attributes in Active Directory records. Choose this method if Macs on the SAN are connected to Active Directory with binding options set to map IDs to uidNumber and gidNumber. Important: To avoid ID conflicts, be sure all computers on the SAN use the same Active Directory domain and the same method of ID mapping. Select the Windows ID mapping method: 1 In Xsan Admin, select Volumes in the SAN Assets list, and choose Edit Volume Settings from the Action pop-up menu (gear). 2 Choose a mapping method from the Windows ID Mapping pop-up menu. If you choose “Use IDs from LDAP (RFC 2307),” you can change the ID numbers used when a directory record doesn’t include a uidNumber or gidNumber attribute. 3 Click OK. Xsan Admin unmounts the volume from clients and controllers and stops the volume before changing the Windows ID mapping method, and then starts the volume and mounts it on each computer that had it mounted. Set SAN user and group quotas You can use Xsan Admin to set quotas on the amount of storage available to a user or group. Note: A group quota includes only folders and files the group owns. Basic access permissions for a folder or a file determine its owner. You can view basic access permissions for an item in the Finder’s Get Info window. For instructions, see “Control file and folder access using the Finder” on page 97. 100 Chapter 6 Manage clients and usersChapter 6 Manage clients and users 101 Set a storage quota for a user or group: 1 In Xsan Admin, select Users and Groups in the SAN Assets list. If you’re not using Xsan Admin to manage users and groups, you’ll see Quotas in the SAN Assets list instead of Users and Groups. 2 Choose a volume from the Volume pop-up menu. 3 Select a user or group in the list. To select multiple users or groups, hold down the Command or Shift key as you select users or groups in the list. To add a user or group, click the Users button or Groups button above the list and then click the Add button (+). 4 Click the Edit button. 5 Enter a hard quota, soft quota, and grace period, and then click OK.Remove a quota: m Select the user or group and choose Delete Quota from the Action pop-up menu (gear). If your Xsan computers connect to another Mac server for user and group accounts, use the Server app or the Workgroup Manager app to create users and groups as needed. The Server app is included with Mac OS X Lion Server. Workgroup Manager is available for Lion Server as part of the Server Admin Tools, which you can download from the AppleCare Support Downloads website at www.apple.com/support/downloads/. If existing users and groups aren’t listed when you click the Add button, open the Users & Groups pane of System Preferences on your computer and make sure it’s connected to the correct network account server (directory server). All computers in the SAN should use the same directory server. From the command line You can also set user quotas using the cvadmin quotas set command in Terminal. For information, see the cvadmin man page or “View or change volume and storage pool settings (cvadmin)” on page 145. About Xsan quotas Xsan enforces two disk space quotas for each user or group you choose to restrict: a soft quota and a hard quota. You can set these in combination to establish clear limits on the amount of storage a user or group can use, while still allowing temporary access to extra space for unexpected storage needs. You specify quotas individually for each volume on a SAN. A user who has no quotas specified can use all the available space on a volume. Soft quota The soft quota is the maximum amount of space a user or group is expected to occupy on a regular basis. It’s soft because it can be exceeded by an amount up to the hard quota for a grace period that you specify. Hard quota The hard quota is an absolute limit on the amount of space a user or group can occupy. Users are prevented from using more space than specified by their hard quota. Grace period Users and groups can exceed the soft quota without penalty, as long as each returns below the soft quota within the grace period you specify. 102 Chapter 6 Manage clients and usersChapter 6 Manage clients and users 103 Soft quotas change to hard quotas If a user or group exceeds the soft quota for a time longer than the grace period, the soft quota is changed to a hard quota. The user or group can’t save additional data on the volume until the user or the group members delete enough old files to bring their usage below the soft quota. Example Suppose you assign Aldo a soft quota of 75 GB, a hard quota of 100 GB, and a grace period of 48 hours. Aldo’s files can occupy up to 75 GB of space at any time, for as long as he needs them. If Aldo is surprised by additional or unusually large files, he can still copy them to the volume, up to a total of 100 GB. He then has 48 hours to remove files and return below the 75 GB soft quota. If he’s still using more than 75 GB after 48 hours, Xsan resets his hard quota to 75 GB and he’s forced to reduce his storage use. Aldo can’t copy or save additional files to the volume until he deletes enough to return below the 75 GB quota. Define SAN users consistently for accurate quotas To be sure that Xsan user quota information is accurate, make sure user names and IDs are consistent on all computers on the SAN. Check user quota status You can use Xsan Admin to check file system quotas and see how much of their allotment users and groups are using. Hard quota (right end of bar) Soft quotas (vertical lines)View quota status: m In Xsan Admin, select “Users and Groups” or Quotas in the SAN Assets list. (You see Users and Groups only if you chose to have Xsan Admin manage your users and groups. Otherwise, you see Quotas.) To see current information, click Refresh at the top of the window. Xsan Admin displays the following information for each user or group: Used: The amount of space the user’s files are occupying. Quota: The soft and hard quotas. For example, “75 MB – 100 MB” indicates a soft quota of 75 MB and a hard quota of 100 MB. Quota Status: The status bar represents the full allocation, from zero on the left to the hard quota on the right. The small vertical line on the bar marks the soft quota. The colored portion of the bar shows how much space the user or group is using. Green indicates that the user or group is below the soft quota. Yellow indicates usage exceeding the soft quota but for a time within the grace period. Red indicates that the user has reached the hard quota, possibly because the soft quota was exceeded beyond the grace period and was changed to a hard quota. You can set up Xsan to notify you by email or text message when a user or group exceeds a soft quota. See “Set up status notifications” on page 119. For more information about quotas and how to set them, see “Set SAN user and group quotas” on page 100. From the command line You can also check user quotas using the cvadmin quotas get command in Terminal. For information, see the cvadmin man page or “View or change volume and storage pool settings (cvadmin)” on page 145. Help users check quotas SAN users who work on client computers but don’t have access to Xsan Admin can use the quota command-line tool to check their quotas. Check a user’s quota from a client computer: 1 Open the Terminal app (in the /Applications/Utilities/ folder). 2 Enter quota -u -g -v and press Return. The quotas for the user and for groups the user belongs to are displayed in a table. The first column reports the volume name. The second column reports how much space the user or group is using on the volume, suffixed with an asterisk if the usage is over the soft limit. The third column reports the soft quota. The fourth column reports the hard quota. Usage and quotas are reported in 1 KB blocks. To see the user quota without the group quotas, omit -g when you enter the command. 104 Chapter 6 Manage clients and usersChapter 6 Manage clients and users 105 Manage client computers remotely Xsan Admin can help you connect to an Xsan client computer so you can observe or control it over the network. Using Xsan Admin, you can:  Start a screen sharing session so you can observe or control another computer.  Open Terminal so you can log in using SSH and control another computer. You can also connect and manage a server in the SAN by using the Server app on a computer that has it installed. Connection options Action menu Control a client using screen sharing You can use the screen sharing feature of Mac OS X to view and control the screen of a SAN client over the network. Xsan Admin can start a screen sharing session with the client. Connect to a client using screen sharing: 1 In Xsan Admin, select Computers in the SAN Assets list. 2 Select the client you want to observe or control. 3 Choose “Connect Using Screen Sharing” from the Action pop-up menu (gear).If you have trouble sharing the screen of a remote computer, check the Sharing pane of System Preferences on the remote computer to make sure Remote Management service is turned on. If you have trouble starting a screen sharing session with an Xsan client, open the Security pane of System Preferences on the client, click Firewall, and make sure the option to block all incoming connections isn’t selected. Connect to a client using SSH in terminal You can use the Secure Shell (SSH) command-line tool to log in to a SAN client over the network. Xsan Admin can start an SSH session with the client or controller. Connect to a client using SSH: 1 In Xsan Admin, select Computers in the SAN Assets list. 2 Select the client you want to connect to. 3 Choose “Connect using ssh” from the Action pop-up menu (gear). If you have trouble making an SSH connection, check the Sharing pane of System Preferences on the remote computer to make sure Remote Login service is turned on. If you have trouble making an SSH connection with an Xsan client, open the Security pane of System Preferences on the client, click Firewall, and make sure the option to block all incoming connections isn’t selected. 106 Chapter 6 Manage clients and users107 To increase SAN security and redundancy, you can add, switch, and monitor Xsan metadata controllers. Every SAN volume you set up is managed by a metadata controller. To be sure that the volume is available to clients even if the primary metadata controller becomes unresponsive, you can set up standby controllers, one of which will assume control of the volume if the primary controller fails. This chapter shows you how to add metadata controllers, set their failover priority, and force volume failover from the primary controller to a standby controller. Add a metadata controller You can add standby metadata controllers to a SAN so that volumes remain available if the primary metadata controller fails. 7 Manage metadata controllersImportant: For best performance, metadata controllers should have Mac OS X Lion Server, and the “Dedicate system resources to server services” option should be turned on in the Server app. Add button Select to view computers already in SAN. Add a metadata controller: 1 Connect the new controller computer to the SAN’s Fibre Channel and Ethernet networks. 2 Open System Preferences, click Xsan, and click Enable Xsan. 3 Open Xsan Admin, select Computers in the SAN Assets list, and then click the Add button (+). 4 When the assistant opens, select the new controller computer in the computer list and click Continue. If the computer doesn’t appear in the list, click Add Remote Computer and add it. 5 On the Authenticate Clients pane, enter the administrator user name and password for the computer. 6 On the Choose Metadata Controllers pane, select the checkbox next to the computer in the list and click Continue. After you add a controller to the SAN, volumes that are mounted on all other controllers are mounted automatically on the new controllers. Volumes that are mounted only on some controllers aren’t mounted automatically on the new controller, but you can mount those volumes manually by selecting Mounts in the SAN Assets list. 108 Chapter 7 Manage metadata controllersChapter 7 Manage metadata controllers 109 Set controller failover priority When the primary metadata controller for a volume fails, Xsan uses the failover priorities of the available standby controllers to decide which one to switch to. Different volumes can be hosted by different metadata controllers, and you can choose a failover priority for each volume. Set a metadata controller’s failover priority: 1 Open Xsan Admin, select Volumes in the SAN Assets list, and select a volume in the list. 2 Choose Edit Failover Priority from the Action pop-up menu (gear). 3 Drag metadata controllers up or down in the list that appears. The closer a metadata controller is to the top of the list, the more likely it is that it will host the volume. 4 Click OK. Switch to a standby metadata controller You can use Xsan Admin to force an active metadata controller to turn over control of a volume to a standby controller. Force failover to a standby metadata controller: 1 Open Xsan Admin and select Volumes in the SAN Assets list. 2 Select the volume in the list and choose “Force failover” from the Action pop-up menu (gear). From the command line You can also switch a volume to a standby metadata controller using the cvadmin fail command in Terminal. For information, see the cvadmin man page or “View or change volume and storage pool settings (cvadmin)” on page 145.Find out which controller is hosting a volume Control of a volume can move from one metadata controller to another as a result of controller failover. You can use Xsan Admin to find out which metadata controller is hosting a volume. The controller that is currently hosting the volume View a volume’s metadata controller: m In Xsan Admin, select Volumes in the SAN Assets list and look in the Hosted By column. From the command line You can also find out which metadata controller is hosting a volume by using the cvadmin command-line tool in Terminal. Open Terminal on the controller and enter: $ sudo cvadmin -e select For more information, see the cvadmin man page or “View or change volume and storage pool settings (cvadmin)” on page 145. List the volumes hosted by a controller You can use Xsan Admin or the cvadmin command-line tool to find out which SAN volumes are being hosted by a metadata controller. List hosted volumes: m In Xsan Admin, select Volumes in the SAN Assets list, and click the title of the Hosted By column to sort by controller. 110 Chapter 7 Manage metadata controllersChapter 7 Manage metadata controllers 111 From the command line You can also find out which volumes are hosted by a metadata controller using the cvadmin select command in Terminal. For information, see the cvadmin man page or “View or change volume and storage pool settings (cvadmin)” on page 145. Change a controller’s IP address Follow these instructions to change the IP address of an Xsan metadata controller. WARNING: To avoid losing data on volumes hosted by the primary metadata controller, you must have a standby metadata controller available for each volume. Change a metadata controller’s IP address: 1 In Xsan Admin, select Computers in the SAN Assets list. 2 If you’re changing the primary metadata controller’s IP address, select a standby metadata controller, and choose Make Primary Controller from the Action pop-up menu. 3 Select the controller whose IP address you wish to change, and choose “Remove Computer from SAN” from the Action pop-up menu (gear). 4 Change the computer’s IP address in the Network pane of System Preferences. 5 Open the Server app, click Alerts, select the alert about the network configuration change, and click Recover to update the service configuration files. You can also manually update the service configuration files from the command line by entering: $ sudo changeip oldIP newIP Replace oldIP with the server’s old IP address, and replace newIP with the server’s new IP address. 6 Restart the computer. 7 With its new address, add the computer back to the SAN as a metadata controller. In Xsan Admin, select Computers in the SAN Assets list and click the Add button (+). If you want to switch control of a volume hosted by the standby controller back to the controller with the new IP address, select the volume in the Volumes pane of Xsan Admin and choose “Force failover” from the Action pop-up menu (gear). You can also force failover from the command line by entering: $ sudo cvadmin -e "fail volume" Replace volume with the name of the Xsan volume.Make a standby controller the primary controller Make a standby metadata controller the primary metadata controller: 1 In Xsan Admin, select Computers in the SAN Assets list. 2 Select the standby metadata controller you want to promote, and choose Make Primary Controller from the Action pop-up menu. Convert a controller to a client If you no longer want a computer to act as a metadata controller for SAN volumes, you can demote the controller to a SAN client. Convert a metadata controller to a client: m In Xsan Admin, select Computers in the SAN Assets list, select the metadata controller in the list, and choose Make Client from the Action pop-up menu (gear). If you can’t choose Make Client, make sure all Xsan clients and metadata controllers are turned on and their status is Ready in Xsan Admin’s Computers list. You can’t demote the primary metadata controller if it’s managing users and groups. Access controller computers remotely Xsan Admin can help you connect to an Xsan metadata controller so you can observe or control it over the network. Using Xsan Admin, you can:  Start a screen sharing session so you can observe or control another computer.  Open Terminal so you can log in using SSH and control another computer. 112 Chapter 7 Manage metadata controllersChapter 7 Manage metadata controllers 113 You can also connect and manage a server in the SAN by using the Server app on a computer that has it installed. Connection options Action menu Control a controller using screen sharing You can use the screen sharing feature of Mac OS X to view and control the screen of a SAN metadata controller over the network. Connect to a metadata controller using screen sharing: 1 In Xsan Admin, select Computers in the SAN Assets list. 2 Select the metadata controller you want to observe or control. 3 Choose “Connect using Screen Sharing” from the Action pop-up menu (gear). If you have trouble sharing the screen of a remote computer, check the Sharing pane of System Preferences on the remote computer and make sure Remote Management service is turned on. If the computer is a Mac server, you can also turn on remote management in the Server app or Server Admin. The Server app is included with Mac OS X Lion Server, and Server Admin is included with Mac OS X Server v10.6 Snow Leopard and earlier. Connect to a controller using SSH in Terminal You can use the Secure Shell (SSH) command-line tool to log in to a SAN metadata controller over the network.Connect to a metadata controller using SSH: 1 In Xsan Admin, select Computers in the SAN Assets list. 2 Select the metadata controller you want to connect to. 3 Choose “Connect using ssh” from the Action pop-up menu (gear). If you have trouble making an SSH connection, check the Sharing pane of System Preferences on the remote computer and make sure Remote Login service is turned on. If the computer is a Mac server, you can also turn on remote login in the Server app or Server Admin. The Server app is included with Mac OS X Lion Server, and Server Admin is included with Mac OS X Server v10.6 Snow Leopard and earlier. Monitor controller status For information about checking or reporting the status of a controller, see these topics:  “Graph SAN resource usage” on page 118  “Set up status notifications” on page 119  “View Xsan logs” on page 120 114 Chapter 7 Manage metadata controllers115 You can use Xsan Admin and related command-line tools to check the condition of a SAN and its components. This chapter shows you how to check the status of a SAN and its volumes and how to set up notifications so you’ll be alerted to changes in the SAN. Check SAN status You can use Xsan Admin to view status and configuration information for the SAN and its components. View the overall status of the SAN: m Open Xsan Admin and select Overview in the SAN Assets list. 8 Monitor SAN statusView a component’s status and configuration information: m Open Xsan Admin, click the Inspector button at the top of the window, and then select the component in the SAN Assets list or in the main pane of the Xsan Admin window. Check volume status You can use Xsan Admin to view the status of a volume. View the status of a volume: m Open Xsan Admin, select Volumes in the SAN Assets list, select the volume, and click the Inspector button at the top of the window. You can also double-click the volume. Monitor RAID devices If a RAID array that belongs to an Xsan volume becomes damaged and unrecoverable due to a failed disk drive or other hardware failure, the data on the volume could be lost. To avoid this possibility, regularly check the state of your RAID hardware. Your RAID system management software might be able to notify you when the state of a drive module or array changes. See the documentation that came with your RAID system. 116 Chapter 8 Monitor SAN statusChapter 8 Monitor SAN status 117 Check free space There are several ways to see how much space is available on a SAN volume or on storage pools in a volume. Available space Check the free space on a volume: m From a client or controller computer that has the volume mounted, select the volume in a Finder window, and look at the size information at the bottom of the window (in Column or List view) or choose File > Get Info. You can also use Disk Utility. m From a computer that has Mac OS X Lion Server but doesn’t have the volume mounted or doesn’t belong to the SAN, open Xsan Admin, click Volumes in the SAN Assets list, look for the volume, and then look at the Available column. The reported size and free space for an Xsan volume doesn’t include space in storage pools that contain only journal data and metadata. Only space on storage pools where users can store files is counted (that is, storage pools set to be used for “Any data” or “User data only”). For example, if you create a volume consisting of four 120 GB storage pools and configure one for journal and metadata only, Xsan Admin reports the size of the volume as 360 GB, not 480 GB. Check the free space on a storage pool: m Open Xsan Admin, select Volumes in the SAN Assets list, look for the storage pool, and then look at the Available column.If you don’t see the storage pools for a volume, click the volume’s disclosure triangle. From the command line You can also check volume free space using the cvadmin stat command, and you can check storage pool free space using the cvadmin show command. For information, see the cvadmin man page or “View or change volume and storage pool settings (cvadmin)” on page 145. Graph SAN resource usage Xsan Admin can display graphs of up to a week of CPU, memory, Ethernet, and Fibre Channel usage data for any computer on the SAN. Choose a SAN computer. Choose a time period. Choose a data type. View usage graphs: m In Xsan Admin, click the Graphs button at the top of the window and use the three pop-up menus in the Graphs window to choose a computer, a data type, and a time interval. Memory and CPU resources used by the file system process (fsm) for a volume are listed under the name of the volume in the Graphs pop-up menu when you choose the volume’s controller from the Computer pop-up menu. From the command line You can also check the file system process’s current CPU and memory usage by using the top command-line tool in Terminal to check the process named fsm on the volume’s controller. For information, see the top man page. 118 Chapter 8 Monitor SAN statusChapter 8 Monitor SAN status 119 Set up status notifications You can set up Xsan to send an email or a text message to notify you or other administrators when:  A controller switches to its backup  A Fibre Channel connection fails  Free space on a volume falls below a specified percentage  A user or group exceeds the designated soft quota To send email notifications outside the local network, the controller needs access to an SMTP server. Set up status notifications: 1 Open Xsan Admin and select Overview in the SAN Assets list. 2 Choose Edit Notifications Settings from the Action pop-up menu (gear). 3 To add a contact, click the Add button (+) and enter an email address. 4 If the address is for an account that will forward the notification as a text message, click the checkbox in the Text Msg column. 5 Choose the conditions that cause a notification to be sent (next to “Notify if”). 6 Enter a sender name. 7 Enter the mail server address in the SMTP Server field. 8 To send a test message to all recipients, click Send Test Notification. 9 Adjust settings as necessary, and then click OK.View Xsan logs You can use Xsan Admin to view the informational and diagnostic messages that Xsan writes to the SAN logs.Fibre Channel connection failures or errors are recorded in the system log. Choose a SAN computer. Location of the selected log file Type to search for entries containing specific text. View the SAN logs: m In Xsan Admin, click the Logs button at the top of the window, and then in the Logs window that appears, use the Computer and Log pop-up menus to choose the log you want to view. To display entries containing a specific name, time, or other text, type in the Search field in the lower-right corner of the window. Check for Fibre Channel connection failures: 1 In Xsan Admin, click the Logs button at the top of the window. 2 In the Logs window that appears, choose the computer in the Computer pop-up menu and choose System Log from the Log pop-up menu. From the command line To see the log for a volume from the command line, look at the log file /Library/Logs/ Xsan/data/volume/log/cvlog. The port mapper process log is in /Library/Logs/Xsan/debug/nssdbg.out. The system log is in /var/log/system.log. 120 Chapter 8 Monitor SAN statusChapter 8 Monitor SAN status 121 Check volume clients You can use Xsan Admin to see a summary of which clients are using a volume. Select to see which computers have a volume mounted. Choose a volume. See how many clients have a volume mounted: m Open Xsan Admin, select Volumes in the SAN Assets list, select the volume in the list, and click the Inspector button at the top of the window. See which clients are using a volume: m Open Xsan Admin, select Mounts in the SAN Assets list, and choose the volume from the Volume pop-up menu. From the command line You can also use the cvadmin who command in Terminal to see a list of volume clients. For information, see the cvadmin man page or “View or change volume and storage pool settings (cvadmin)” on page 145.122 Use this chapter to find solutions to common problems you might encounter while working with a SAN. Look here for solutions to common problems you might encounter while setting up, managing, or using an Xsan SAN. If you can’t connect to a computer using Xsan Admin If there’s a firewall between the computer you’re using Xsan Admin on and the SAN computer, make sure TCP port 311 is open on the firewall. If you can’t enable or install the Xsan software If you want to use Xsan on a computer with Mac OS X Lion or Lion Server, but you don’t see the Xsan pane in System Preferences, make sure the computer has a Fibre Channel interface. If you can’t install Xsan using an Xsan Install Disc for Xsan 2.2, make sure the computer has Mac OS X or Mac OS X Server v10.6 Snow Leopard. Mac OS X Lion includes Xsan 2.3, so you can’t use the Xsan Install Disc with it. You can’t use Mac OS X or Mac OS X Server versions earlier than v10.6 with Xsan 2.3. If computers aren’t listed in Xsan Admin If a computer you want to add to the SAN as a metadata controller or client isn’t listed in Xsan Admin, make sure:  You’ve enabled the Xsan software on the computer.  The computer is turned on.  The computer isn’t in sleep. 9 Solve SAN problemsChapter 9 Solve SAN problems 123  The computer is on the same TCP/IP subnets as the other SAN components. (If you’re using a private and a public Ethernet network, all SAN components must be connected to both networks.)  The computer is connected to the SAN’s Fibre Channel networks. If you can’t mount a volume on a client  Restart the client computer, and then try mounting the volume again.  Check that all Fibre Channel cables are plugged in.  Make sure that no other volumes mounted on the client have the same name as the Xsan volume. If you can’t unmount a volume on a client  Make sure no processes are using the volume.  Restart the client computer, and then try unmounting the volume again. If RAID LUNs aren’t accessible over Fibre Channel  Restart the computer that doesn’t see the LUNs.  Check the configuration of the Fibre Channel switch to be sure the SAN computers and storage devices are in the same Fibre Channel zone. If you have problems using command-line tools If you get the response “insufficient administrator privileges” when you run the cvadmin command-line tool, make sure you have root user privileges when you use the tool. Log in as the root user or use the sudo command to run the tool. For example: $ sudo cvadmin If a LUN doesn’t have as much space as expected To make striping across all LUNs possible, Xsan adjusts LUN sizes to make LUNs in a storage pool the same size as the smallest LUN in the pool. Xsan doesn’t use the extra space on larger LUNs if you mix LUNs of different sizes in a storage pool. If you can’t rename an Xsan volume in the Finder Xsan doesn’t let a mounted Xsan volume be renamed using the Finder, but you can use Xsan Admin to rename the volume. See “Rename a volume” on page 85.If you can’t add a storage pool Some words are reserved and can’t be used to name a storage pool. If a storage pool is used for user data, the first eight characters of the storage pool name can’t be a reserved word. If you enter a reserved word as the storage pool name, the OK button in the storage pool sheet is dimmed. Examples include: Affinity, Exclusive, Journal, Log, MetaData, Regular, and Type. For a register of reserved words, see the cvfs_config man page by entering this command in Terminal: $ man -M /System/Library/Filesystems/acfs.fs/Contents/man/ 4 cvfs_config If Fibre Channel performance is poor With some Fibre Channel switches, mismatched optical transceivers (GBICs) can cause Fibre Channel communication errors and degrade SAN performance. Check with the manufacturers of your Fibre Channel switches to see if you should use identical transceivers (same manufacturer and model number) on both ends of your Fibre Channel cables. However, with Cisco Fibre Channel switches, you should use a Cisco transceiver on the end of a cable that plugs into the switch and another qualified transceiver at the other end of the cable. For Fibre Channel hardware compatibility information, see the AppleCare Support article at support.apple.com/kb/HT1769. If a client can’t use a volume after a Fibre Channel interruption If a client loses its Fibre Channel connection to the SAN (for example, because a cable is unplugged), the client might not recognize LUNs in an Xsan volume after the connection is restored. If this happens, restart the client to remount the volume. If problems persist, restart all SAN devices. Restart RAID systems first, then continue with SAN controllers, and finally, restart all clients. Check whether a computer is seeing Xsan volume LUNs: m Open Disk Utility on the computer and look for the LUNs in the list of disks and volumes. From the command line You can also check for accessible LUNs using the cvlabel -l command or the diskutil list command in Terminal. For information, see the cvlabel or diskutil man page. 124 Chapter 9 Solve SAN problemsChapter 9 Solve SAN problems 125 If you can’t add LUNs to a storage pool You can’t add a LUN to a storage pool unless the LUN is at least as large as the smallest LUN you added when you created the pool. You can add a larger LUN, but space beyond the smallest LUN size isn’t used. You can only expand storage pools that can be used for user data. You can’t add a LUN to a storage pool if the storage pool is used only for journaling and metadata. To add journaling and metadata storage, add another storage pool that can be used for journaling and metadata. Xsan also won’t let you add a LUN to a storage pool if adding the LUN will fragment the storage pool so much that performance suffers. Check the common LUN size for a storage pool: m In Xsan Admin, select Volumes in the SAN Assets list and click disclosure triangles in the list of volumes to show the LUNs in the storage pool of interest. Compare the listed LUN sizes. Check the data types a storage pool is used for: m In Xsan Admin, select Volumes in the SAN Assets list then click disclosure triangles in the list of volumes to show the storage pool of interest. Double-click the storage pool in the list and look next to “Used For” in the Inspector window. If the capacity of a larger LUN is Listed as 2 terabytes If a LUN that doesn’t yet belong to a storage pool is listed in Xsan Admin with a capacity of 2 TB, even though you know it’s larger (which can happen if you used the LUN with an earlier version of Xsan), try relabeling the LUN. Relabel a LUN: 1 In Xsan Admin, select LUNs in the SAN Assets list. 2 Click LUNs, select the LUN in the list, and choose “Remove LUN label” from the Action pop-up menu (gear). 3 With the LUN still selected, choose “Change LUN label” from the Action pop-up menu, and enter a label. If file copying doesn’t finish If the Ethernet connection to a metadata controller is lost, Finder file-copy operations in progress on clients might not finish, even though the volume successfully fails over to a standby controller. Let the copy operation finish: m Reconnect the disconnected controller to the SAN’s Ethernet network.If a volume unexpectedly restarts Xsan can restart a volume for a variety of reasons, including controller restart and volume failover. The notification is the same in all cases, but you can examine the log files for more details. View the logs: 1 Open Xsan Admin and click the Logs button at the top of the window. 2 In the Logs window that appears, use the Computer and Log pop-up menus to choose a log. 126 Chapter 9 Solve SAN problems127 This appendix shows you how to upgrade your Xsan 2 SAN to Xsan 2.3. Follow the instructions in this appendix to upgrade an existing Xsan 2 SAN and its volumes to Xsan 2.3. Upgraded metadata controllers must have Mac OS X Lion Server. Upgraded SAN clients must have Mac OS X Lion or Lion Server, which include Xsan 2.3, or Mac OS X or Mac OS X Server v10.6 with Xsan 2.2.1 or later installed. Before you begin Review the following information before you upgrade your SAN. If you’re not running Xsan 2.0 or later This appendix shows you how to upgrade from Xsan 2.0 or later. For help upgrading from an earlier version of Xsan, see the Xsan 2 Migration Guide, Second Edition, available at www.apple.com/xsan/resources/. Lion or Lion Server? The Xsan file system is included with Mac OS X Lion and Lion Server. The Xsan Admin app is included with Mac OS X Lion Server. Unless otherwise indicated, a statement in this appendix about Mac OS X Lion also applies to Mac OS X Lion Server. However, if you use Xsan Admin to manage SAN users and groups, you must have Mac OS X Lion Server on your metadata controllers to create the Open Directory master and its replicas. Which procedure? This appendix contains two sets of instructions:  Follow “Upgrade your SAN software” below if you want to upgrade your current metadata controllers to Xsan version 2.3 and Mac OS X Lion Server.  Follow “Upgrade SAN hardware and software” on page 132 if you need to replace your current metadata controllers with Intel-based computers in addition to upgrading to Xsan 2.3 and Mac OS X Lion Server. A Appendix Upgrade to Xsan 2.3128 Appendix A Upgrade to Xsan 2.3 Version compatibility For information about the compatibility of Xsan 2.3 metadata controllers and clients with earlier Xsan versions and with StorNext controllers and clients, see “Version compatibility” on page 13. Upgrade your SAN software Follow these instructions if you want to keep using your current metadata controllers and upgrade them to Xsan 2.3 and Mac OS X Lion Server. If you need to replace your metadata controllers, follow the instructions in “Upgrade SAN hardware and software” on page 132. The instructions in this section show you how to upgrade your SAN’s metadata controllers one at a time so that existing volumes remain available. As each controller is upgraded, volumes it is hosting fail over to standby controllers. However, if you enable extended attributes on a volume after upgrading to Xsan 2.3, the volume is not mounted on clients until the conversion process finishes. This process can take hours, depending on the number of files on the volume; the volume is not available during this time. Summary: 1 Back up your SAN volumes. 2 Disable Spotlight on all volumes. 3 Upgrade the primary controller to Mac OS X Lion Server. 4 Upgrade the remaining controllers. 5 Reestablish Open Directory replicas. 6 Upgrade the SAN clients. 7 Enable extended attributes. 8 Change filename case sensitivity. 9 Reenable Spotlight. Instructions for these steps are on the following pages. Step 1: Back up your SAN volumes Before you begin, make a backup copy of the files on your SAN volumes. Step 2: Disable Spotlight on all volumes Before upgrading your SAN computers to Mac OS X Lion or Lion Server, disable Spotlight on all Xsan volumes during the upgrade.Appendix A Upgrade to Xsan 2.3 129 Disable Spotlight on a volume: 1 Open your current version of Xsan Admin. 2 In Xsan Admin, select Volumes in the SAN Assets list. 3 Select the volume and choose Edit Volume Settings from the Action pop-up menu (gear). 4 Click to deselect “Enable on this volume” next to Spotlight. Step 3: Upgrade the primary controller to Mac OS X Lion Server To upgrade to Xsan 2.3, you must upgrade your metadata controllers to Mac OS X Lion Server. Important: If you use Xsan Admin to manage SAN users and groups, upgrade your primary controller (the controller hosting the SAN’s Open Directory master) before you upgrade standby controllers. Identify your Open Directory primary controller: m If you’re using Xsan Admin to manage users and groups, open Xsan Admin, select Overview in the SAN Assets list, and look for the controller that has the user icon next to its name. Upgrade that controller first. Upgrade the controller to Mac OS X Lion Server: m Open the Mac App Store on the controller you want to upgrade, and purchase Mac OS X Lion. After you purchase Mac OS X Lion, the Mac OS X Install Assistant opens. It recognizes that you’re upgrading from Mac OS X Server v10.6, and upgrades to Lion Server. If the metadata controller you’re upgrading has Mac OS X Server v10.5, upgrade it to v10.6 before purchasing Mac OS X Lion. After upgrading Mac OS X Server v10.5 to v10.6:  Use Software Update to update to the latest version of Mac OS X Server v10.6  Use Software Update to update to Xsan 2.2.1 or later. You must update Xsan because there are underlying differences between Xsan 2.2 for Mac OS X Server v10.5 and Xsan 2.2 for Mac OS X Server v10.6. Upgrading to Mac OS X Lion Server upgrades Xsan to version 2.3. From this point forward, use Xsan Admin only on a computer with Mac OS X Lion Server. Step 4: Upgrade the remaining controllers Repeat step 3 on each additional SAN metadata controller. When all controllers have Mac OS X Lion Server, which includes Xsan 2.3, continue with the next step.130 Appendix A Upgrade to Xsan 2.3 Step 5: Reestablish Open Directory replicas If you don’t use Xsan Admin to manage SAN users and groups, skip to the next step. If you use Xsan Admin to manage SAN users and groups, you now have an Open Directory master on your primary controller (the first controller you upgraded in step 3). However, you must reestablish replicas of that directory on your other controllers. Recreate the directory replicas: m Open Xsan Admin on one controller and select Computers in the SAN Assets list. A dialog prompts you to recreate the replicas. If you’re not asked to replicate the directory, see if you have upgraded all controllers in the SAN to Mac OS X Lion Server, which includes Xsan 2.3, and then try again. If the replication prompt still doesn’t appear, select a controller in the Computers pane in Xsan Admin and choose Make Open Directory Replica from the Action pop-up menu (gear). Step 6: Upgrade the SAN clients When all SAN controllers have Mac OS X Lion Server, upgrade the SAN clients.  If you’re keeping client computers in the SAN, upgrade them to Mac OS X Lion or Lion Server.  If you aren’t upgrading a client computer, and it has Mac OS X or Mac OS X Server v10.6, upgrade it to Xsan 2.2.1 or later.  If a client computer has Mac OS X or Mac OS X Server 10.5 or earlier, you must upgrade it to v10.6 to use it in your Xsan 2.3 SAN.  If you have client computers with PowerPC processors, you can’t use them in your Xsan 2.3 SAN. You can replace them with Macs that have Intel processors and Fibre Channel ports or adapters. Upgrade Mac OS X and Xsan: m Open the Mac App Store on the client computer you want to upgrade, and purchase Mac OS X Lion. After you purchase Mac OS X Lion, the Mac OS X Install Assistant opens. It upgrades Mac OS X v10.6 to Mac OS X Lion, or Mac OS X Server v10.6 to Mac OS X Lion Server. If the client computer you’re upgrading has Mac OS X or Mac OS X Server v10.5, upgrade it to v10.6 before purchasing Mac OS X Lion. After upgrading to v10.6:  Use Software Update to update to the latest version of Mac OS X or Mac OS X Server v10.6  Use Software Update to update to Xsan 2.2.1 or later. You must update Xsan because there are underlying differences between Xsan 2.2 for Mac OS X v10.5 and Xsan 2.2 for Mac OS X v10.6.Appendix A Upgrade to Xsan 2.3 131 Upgrading to Mac OS X Lion or Lion Server upgrades Xsan to version 2.3. If SAN volumes don’t mount on a client upgraded to Mac OS X Lion or Lion Server, use the Xsan pane of System Preferences on the client to make sure Xsan is enabled. Upgrade Xsan only: m On a client computer with Mac OS X or Mac OS X Server v10.6, choose Software Update from the Apple menu and update to Xsan 2.2.1 or later. If the client computer has Mac OS X or Mac OS X Server v10.5 or earlier, you must upgrade it to v10.6 in order to use it in your Xsan 2.3 SAN. If Xsan Admin displays a message about “Incorrect Search Policy,” use the Login Options section of the Users & Groups pane of System Preferences (the Accounts pane in Mac OS X v10.6) to connect to the correct network account server (directory server). Step 7: Enable extended attributes If you have only Macs on your SAN, enable extended attributes on your SAN volumes to improve volume performance and efficiency. Important: Enabling extended attributes can’t be undone. WARNING: To avoid data loss, clients with Quantum’s StorNext File System (Windows, AIX, IRIX, Linux, and Solaris computers) must not access volumes that use extended attributes. Enable extended attributes: 1 Open Xsan Admin and select Volumes in the SAN Assets list. 2 Select the volume and choose Edit Volume Settings from the Action pop-up menu (gear). 3 Click to select “Enable on this volume” next to Extended Attributes. The time it takes to convert the volume to use extended attributes depends on the number of files on the volume—it might take several hours for a large volume. During this time, the volume is mounted only on the converting controller and can’t be used by clients. The volume is mounted on clients and other controllers when the conversion is finished. Step 8: Change filename case sensitivity If all your SAN computers have Mac OS X Lion or Lion Server, you can specify whether a volume ignores capitalization in filenames. For example, a volume can consider myfile, MyFile, and MYFILE to be the same or different filenames. For best performance with volumes that you share using the SMB protocol, make them case insensitive.132 Appendix A Upgrade to Xsan 2.3 Change filename case sensitivity for a volume: 1 In Xsan Admin, select Volumes in the SAN Assets list. 2 Select the volume and choose Edit Volume Settings from the Action pop-up menu (gear). 3 Select or deselect the checkbox next to Case Insensitivity and click OK. When you change case sensitivity, Xsan checks all existing filenames to make sure the change won’t result in filenames being considered the same. This check can take a while. If Case Insensitivity is selected, the volume considers filenames to be the same if they’re spelled alike but capitalized differently. If Case Insensitivity is not selected, the volume considers filenames to be different if they’re spelled alike but capitalized differently. Note: After you click OK, the volume is unmounted from all Xsan computers, and then remounted. Step 9: Reenable Spotlight If you disabled Spotlight to upgrade SAN computers to Mac OS X Lion or Lion Server, reenable it now. Enable Spotlight on a volume: 1 In Xsan Admin, select Volumes in the SAN Assets list. 2 Select the volume and choose Edit Volume Settings from the Action pop-up menu (gear). 3 Click to select “Enable on this volume” next to Spotlight. Upgrade SAN hardware and software Follow these instructions if, as part of your Xsan 2.3 upgrade, you must replace PowerPC-based computers with Intel-based computers. (Xsan 2.3 requires all SAN computers to have Intel processors.) Summary: 1 Back up your SAN volumes. 2 Disable Spotlight on all volumes. 3 Adjust volume failover priorities. 4 Convert all standby controllers to clients. 5 Unmount and stop all volumes. 6 Connect new computers to the SAN. 7 Migrate the primary controller to a new computer. 8 Migrate previous standby controllers to new client computers. 9 Convert clients to standby controllers.Appendix A Upgrade to Xsan 2.3 133 10 Migrate remaining SAN clients. 11 Enable extended attributes. 12 Change filename case sensitivity. 13 Reenable Spotlight. 14 Recreate your MultiSAN configuration. Step 1: Back up your SAN volumes Before you begin, make a backup copy of the files on your SAN volumes. Step 2: Disable Spotlight on all volumes Disable Spotlight on all Xsan volumes during the migration to new SAN computers. Disable Spotlight on all volumes: 1 In Xsan Admin, select Volumes in the SAN Assets list. 2 Select a volume and choose Edit Volume Settings from the Action pop-up menu (gear). 3 Click to deselect “Enable on this volume” next to Spotlight. 4 Repeat for all volumes in the SAN. Step 3: Adjust volume failover priorities If you use the MultiSAN capability of Xsan to host volumes on different subsets of the available controllers, adjust volume failover priorities so that all volumes can fail over to the primary metadata controller. Make sure all volumes will fail over to the new controllers: 1 Open Xsan Admin and select Volumes in the SAN Assets list. 2 Select a volume and choose Edit Failover Priority from the Action pop-up menu (gear). 3 Click to select the primary metadata controller in the list, and click OK. 4 Repeat for all volumes in the SAN. Step 4: Convert all standby controllers to clients Identify the primary metadata controller, and then convert all other metadata controllers to Xsan clients. If a metadata controller is hosting a volume when you convert it to a client, another metadata controller begins hosting the volume. When you finish this step, the primary metadata controller is hosting all SAN volumes. Identify the Open Directory primary controller: m If you’re using Xsan Admin to manage users and groups, open Xsan Admin, select Overview in the SAN Assets list, and look for the controller that has the user icon next to its name. Don’t convert that controller to a client.134 Appendix A Upgrade to Xsan 2.3 Convert a metadata controller to a client: m In Xsan Admin, select Computers in the SAN Assets list, select the metadata controller in the list, and choose Make Client from the Action pop-up menu (gear). If you can’t choose Make Client, make sure all Xsan clients and metadata controllers are turned on and their status is Ready in Xsan Admin’s Computers list. Step 5: Unmount and stop all volumes Before migrating data from your old metadata controllers to new computers, stop all SAN volumes so they can’t be changed. Unmount and stop al volumes: 1 In Xsan Admin, select Mounts in the SAN Assets list. 2 Choose a volume from the Volume pop-up menu. 3 Select all clients in the list and click the Unmount button. To select more than one client, hold down the Command or Shift key as you select clients in the list. 4 Choose Stop Volume from the Action pop-up menu (gear). 5 Repeat for all volumes in the SAN. Step 6: Connect new Macs to the SAN Connect your new Macs to the SAN’s Ethernet and Fibre Channel networks. If necessary, remove old computers to make ports available. Don’t go through the setup assistant on the new Macs yet. Important: Mac OS X Lion Server is recommended for all SAN controllers and is required if you use Xsan Admin to manage users and groups. Make sure any client you want to convert to a controller has Mac OS X Lion Server. Step 7: Migrate the primary metadata controller Use the server setup assistant to migrate server data from the old primary controller to a new server. Migrate the primary controller to a new server: 1 Use Xsan Admin to make sure the primary metadata controller is in the failover priority list for every SAN volume. 2 Make sure Xsan Admin isn’t open on any computer that can connect to a metadata controller. Xsan Admin can become confused if it’s open when a SAN computer’s IP address migrates to a new computer.Appendix A Upgrade to Xsan 2.3 135 3 Restart the old primary metadata controller in target disk mode, so the server setup assistant can transfer data from it to a new server. You can restart in target disk mode by holding down the T key when the computer starts up. 4 Turn on the new server that you want to become the primary metadata controller, and wait for the server setup assistant’s Welcome pane to appear. 5 Proceed through the server setup assistant to the "Transfer an Existing Mac Server” pane, select “Transfer the information from an existing server,” and click Continue. 6 Connect the old primary metadata controller to the new server with a FireWire cable, and when you’re ready to begin transferring data, click Continue in the Transfer Your Mac Server pane. 7 After the server setup assistant finishes transferring data, proceed through the remaining setup panes. 8 Shut down the old primary metadata controller, and disconnect it from the Ethernet and Fibre Channel networks. Don’t start up the old primary metadata controller while it’s connected to the Ethernet networks, because it has the same IP address as the new server you migrated it to. Step 8: Migrate former standby controllers Use the server setup assistant to migrate server data from the former standby metadata controllers, which you converted to SAN clients in an earlier step, to new servers. You convert the new servers to metadata controllers in the next step. Migrate a former standby controller to a new server: 1 Make sure Xsan Admin isn’t open on any computer that can connect to a metadata controller. Xsan Admin can become confused if it’s open when a SAN computer’s IP address migrates to a new computer. 2 Restart the former standby metadata controller in target disk mode, so the server setup assistant can transfer data from it to a new server. You can restart in target disk mode by holding down the T key when the computer starts up. 3 Turn on the new server that you want to become the primary metadata controller, and wait for the server setup assistant’s Welcome pane to appear. 4 Proceed through the server setup assistant to the "Transfer an Existing Mac Server” pane, select “Transfer the information from an existing server,” and click Continue. 5 Connect the former standby metadata controller to the new server with a FireWire cable, and when you’re ready to begin transferring data, click Continue in the Transfer Your Mac Server pane.136 Appendix A Upgrade to Xsan 2.3 6 After the server setup assistant finishes transferring data, proceed through the remaining setup panes. 7 Shut down the former standby metadata controller, and disconnect it from the Ethernet and Fibre Channel networks. Don’t start up the former standby metadata controller while it’s connected to the Ethernet networks, because it now has the same IP address as the new server you migrated it to. Step 9: Convert clients to standby controllers You converted your old standby metadata controllers to SAN clients in an earlier step, and after migrating them to new servers in the previous step, the new servers are still SAN clients. You need to convert those clients to standby controllers. Convert a client to a standby controller: 1 Open Xsan Admin on the primary controller and select Computers in the SAN Assets list. 2 Select the client, and then choose Make Controller from the Action pop-up menu (gear). Step 10: Migrate or upgrade SAN clients When your SAN controllers all have Mac OS X Lion Server, you can migrate or upgrade the SAN clients.  If you’re replacing client computers in the SAN with new computers, use the Mac OS X Lion setup assistant or the Mac OS X Lion Server setup assistant to migrate data from old client computers to their replacements.  If you’re keeping client computers in the SAN, upgrade them to Mac OS X Lion or Lion Server.  If you aren’t upgrading a client computer, and it has Mac OS X or Mac OS X Server v10.6, upgrade to Xsan 2.2.1 or later.  If a client computer has Mac OS X or Mac OS X Server 10.5 or earlier, you must upgrade it to v10.6 to use it in your Xsan 2.3 SAN.  If you have client computers with PowerPC processors, you can’t use them in your Xsan 2.3 SAN. You can replace them with Macs that have Intel processors and Fibre Channel ports or adapters. Migrate to a new computer: 1 Make sure Xsan Admin isn’t open on any computer that can connect to a metadata controller. Xsan Admin can become confused if it’s open when a SAN computer’s IP address migrates to a new computer. 2 Turn on the new computer, and wait for the setup assistant to appear.Appendix A Upgrade to Xsan 2.3 137 3 Proceed through the setup assistant to the pane that offers to transfer data from an existing computer, and choose to transfer data. Connect the old computer and the new computer with a FIreWire cable, and restart the old computer in target disk mode. You can restart in target disk mode by holding down the T key when the computer starts up. If you aren’t using FireWire to connect the computers, follow the onscreen instructions for connecting them. 4 After the setup assistant finishes transferring data, proceed through the remaining setup panes. 5 Shut down the old computer, and disconnect it from the Ethernet and Fibre Channel networks. The old computer has the same IP address as the new computer you migrated it to. If SAN volumes don’t mount on a client migrated to Mac OS X Lion or Lion Server, use the Xsan pane of System Preferences on the client to make sure Xsan is enabled. Upgrade Mac OS X and Xsan: m Open the Mac App Store on the client computer you want to upgrade, and purchase Mac OS X Lion. After you purchase Mac OS X Lion, the Mac OS X Install Assistant opens. It upgrades Mac OS X v10.6 to Mac OS X Lion, or Mac OS X Server v10.6 to Mac OS X Lion Server. If the client computer you’re upgrading has Mac OS X or Mac OS X Server v10.5, upgrade it to v10.6 before purchasing Mac OS X Lion. After upgrading to v10.6:  Use Software Update to update to the latest version of Mac OS X or Mac OS X Server v10.6  Use Software Update to update to Xsan 2.2.1 or later. You must update Xsan because there are underlying differences between Xsan 2.2 for Mac OS X v10.5 and Xsan 2.2 for Mac OS X v10.6. Upgrading to Mac OS X Lion or Lion Server upgrades Xsan to version 2.3. If SAN volumes don’t mount on a client upgraded to Mac OS X Lion or Lion Server, use the Xsan pane of System Preferences on the client to make sure Xsan is enabled. Upgrade Xsan only: m On a client computer with Mac OS X or Mac OS X Server v10.6, choose Software Update from the Apple menu and update to Xsan 2.2.1 or later. If the client computer has Mac OS X or Mac OS X Server 10.5 or earlier, you must upgrade it to v10.6 in order to use it in your Xsan 2.3 SAN. If Xsan Admin displays a message about “Incorrect Search Policy,” use the Login Options section of the Users & Groups pane of System Preferences (the Accounts pane in Mac OS X v10.6) to connect to the correct network account server (directory server).138 Appendix A Upgrade to Xsan 2.3 Step 11: Enable extended attributes If you have only Macs on your SAN, enable extended attributes on your SAN volumes to improve volume performance and efficiency. Important: Enabling extended attributes can’t be undone. WARNING: To avoid data loss, clients with Quantum’s StorNext File System (Windows, AIX, IRIX, Linux, and Solaris computers) must not access volumes that use extended attributes. Enable extended attributes: 1 Open Xsan Admin and select Volumes in the SAN Assets list. 2 Select the volume and choose Edit Volume Settings from the Action pop-up menu (gear). 3 Click to select “Enable on this volume” next to Extended Attributes. The time it takes to convert the volume to use extended attributes depends on the number of files on the volume—it might take several hours for a large volume. During this time, the volume is mounted only on the converting controller and can’t be used by clients. The volume is mounted on clients and other controllers when the conversion is finished. Step 12: Change filename case sensitivity If all your SAN computers have Mac OS X Lion or Lion Server, you can specify whether a volume ignores capitalization in filenames. For example, a volume can consider myfile, MyFile, and MYFILE to be the same or different filenames. For best performance with volumes that you share using the SMB protocol, make them case insensitive. Change filename case sensitivity for a volume: 1 In Xsan Admin, select Volumes in the SAN Assets list. 2 Select the volume and choose Edit Volume Settings from the Action pop-up menu (gear). 3 Select or deselect the checkbox next to Case Insensitivity and click OK. When you change case sensitivity, Xsan checks all existing filenames to make sure the change won’t result in filenames being considered the same. This check can take a while. If Case Insensitivity is selected, the volume considers filenames to be the same if they’re spelled alike but capitalized differently. If Case Insensitivity is not selected, the volume considers filenames to be different if they’re spelled alike but capitalized differently. Note: After you click OK, the volume is unmounted from all Xsan computers, and then remounted.Appendix A Upgrade to Xsan 2.3 139 Step 13: Reenable Spotlight If you disabled Spotlight to upgrade SAN computers to Mac OS X Lion or Lion Server, reenable it now. Enable Spotlight on a volume: 1 In Xsan Admin, select Volumes in the SAN Assets list. 2 Select the volume and choose Edit Volume Settings from the Action pop-up menu (gear). 3 Click to select “Enable on this volume” next to Spotlight. Step 14: Recreate your MultiSAN configuration If you use the MultiSAN capability of Xsan to host volumes on subsets of available controllers, your volume failover priorities were reset when you converted standby metadata controllers to clients in step 3. You can now adjust failover priorities to recreate your MultiSAN configuration. Specify which controllers host a volume: 1 In Xsan Admin, select Volumes in the SAN Assets list. 2 Select a volume and choose Edit Failover Priority from the Action pop-up menu (gear). 3 Click to select or deselect controllers in the list, and click OK. 4 Repeat for all volumes in the SAN.140 Here’s how to connect Windows, Solaris, UNIX, AIX, IRIX, or Linux clients to an Xsan SAN. Xsan is fully compatible with Quantum’s StorNext File System, so you can set up Mac Pro, Xserve, and RAID systems to act as SAN controllers and storage for Windows, Sun Solaris, UNIX, IBM AIX, SGI IRIX, or Linux clients that run StorNext software. For information about adding Macintosh clients to an existing StorNext SAN, see the StorNext Product Bulletin #42, available at www.quantum.com/ServiceandSupport/ SoftwareandDocumentationDownloads/SupportBulletins/Index.aspx. Compatible software versions For information about versions of Xsan and StorNext controllers and clients that can be used on the same SAN, see “Version compatibility” on page 13. Terminology Note these differences in terminology between StorNext and Xsan: StorNext term Equivalent Xsan term file system volume file system server (FSS) controller (or metadata controller) stripe group storage pool B Appendix Combine Xsan controllers and StorNext clientsAppendix B Combine Xsan controllers and StorNext clients 141 License An Xsan license is included with the purchase of Mac OS X Lion or Lion Server. The Xsan license for a client computer with Mac OS X or Mac OS X Server v10.6 requires a serial number, which can be the single-copy serial number printed on the Xsan Install Disc sleeve included in an Xsan 2.2 package, or it can be a serial number you purchased separately. Licenses for StorNext are included with the purchase of the StorNext software from Quantum. Xsan clients do not use or count as StorNext File System client licenses. Add StorNext clients to an Xsan SAN You can use Quantum’s StorNext software to access an Xsan SAN from a Windows, UNIX, Sun Solaris, IBM AIX, SGI IRIX, or Linux computer. Add a StorNext client to an Xsan SAN: 1 Install the StorNext File System software on the non-Macintosh client following the instructions that Quantum provides in the StorNext package. 2 Connect the non-Macintosh client to the SAN’s Fibre Channel and Ethernet networks. 3 Duplicate the Macintosh Xsan controller’s shared secret file on the non-Macintosh client. The shared secret file is named .auth_secret. On a Macintosh Xsan controller, it’s stored in the folder /Library/Preferences/Xsan/. Copy the file (using the same name) to the non-Macintosh client. On SGI IRIX, Sun Solaris, IBM AIX, and Linux StorNext clients, put the file in /usr/cvfs/config/. On Windows clients, put the file in \%cvfsroot%\config\, where %cvfsroot% is the folder where you installed StorNext. Important: This file contains sensitive information. Secure the file for read/write access by the root user or Windows administrator only. 4 Place a StorNext license file for your non-Macintosh clients on the Macintosh Xsan controller. On the Xsan controller, put the file (named license.dat) in the folder /Library/Preferences/Xsan/. Contact Quantum to obtain a license file for your non-Macintosh clients.142 You can use Xsan shell commands and configuration files to work with a SAN from the command line. You can use the shell commands and configuration files described here to access, set up, and manage Xsan SANs, LUNs, storage pools, and volumes from the command line. The Terminal app is the Mac OS X gateway to the BSD command-line interface (UNIX shell command prompt). Each window in Terminal contains a complete command-line execution context, called a shell, that is separate from all other execution contexts. Although you can use any shell of your choice, the examples in this book assume that you’re using bash, the standard Mac OS X shell. Use shell commands The Xsan command-line utilities are located in /System/Library/Filesystems/acfs.fs/ Contents/bin/. Many commands used to manage Xsan must be executed by the root user (also known as the superuser). If you get a message such as “permission denied,” the command probably requires root user privileges. To execute a single command with root user privileges, begin the command with sudo (short for superuser do). For example: $ sudo cvfsck -n MyVolume If you haven’t used sudo recently, you’re prompted for the password for your administrator account. Send commands to remote computers To use commands on a remote computer, first use SSH to log in to the other computer: $ ssh user@computer Replace user with the name of a user account on the remote computer and computer with its IP address or DNS name. C Appendix Use command-line toolsAppendix C Use command-line tools 143 If you have trouble making an SSH connection, check the Sharing pane of System Preferences on the remote computer and make sure Remote Login service is turned on. View the man pages Detailed documentation for Xsan command-line utilities is available in UNIX-style man pages. A command’s man page includes information about the command, its options, parameters, and proper use. The man pages for Xsan commands are located in /System/Library/Filesystems/acfs.fs/Contents/man/. To view a man page, enter: $ man command Replace command with the command you want information about. Notation conventions These conventions are used throughout the command descriptions: Notation Indicates fixed-width font A command or other text entered in a Terminal window $ A shell prompt [text_in_brackets] An optional parameter (one|other) Alternative parameters (enter one or the other) italicized A parameter you must replace with a value [...] A parameter that can be repeated A displayed value that depends on your SAN configuration Install Xsan from the command line Xsan is installed with Mac OS X Lion and Lion Server. You don’t install Xsan separately on computers with Lion or Lion Server. You can install Xsan on SAN client computers that have Mac OS X or Mac OS X Server version 10.6 Snow Leopard. Install Xsan from the command line: 1 On a SAN client computer that has Mac OS X or Mac OS X Server v10.6, insert the Xsan Install Disc. 2 Open the Terminal app (in the /Applications/Utilities/ folder). 3 Enter one of these commands to install the components:144 Appendix C Use command-line tools  To install the Xsan file system and Xsan Admin app, enter: $ sudo installer -pkg /volumes/Xsan\ Install\ Disc/Install\ Xsan.mpkg -target /  To install only the Xsan Admin app, enter: $ sudo installer -pkg /volumes/Xsan\ Install\ Disc/Install\ XsanAdminApp.pkg/ -target / Install Xsan on a computer that has no keyboard or monitor: 1 Log in to a computer that has a keyboard and monitor, and then insert the Xsan Install Disc. 2 Open the Terminal app (in the /Applications/Utilities/ folder). 3 In Terminal, enter the following command to copy the Xsan installer package to a remote SAN client computer that has Mac OS X or Mac OS X Server v10.6: $ scp -r /Volumes/Xsan\ Install\ Disc/Install\ Xsan.mpkg user@ remotehost:/tmp/ Replace user with the name of an administrator user on the remote computer and remotehost with the IP address or DNS name of the computer you want to install on. To install only the Xsan Admin app, enter: $ scp -r /Volumes/Xsan\ Install\ Disc/Other\ Installs/XsanAdmin.mpkg/ user@remotehost:/tmp/ 4 Log in to the remote computer: $ ssh user@remotehost Replace user and remotehost with the same information as in the previous step. If you have trouble making an SSH connection, check the Sharing pane of System Preferences on the remote computer and make sure Remote Login service is turned on. 5 Run the installer on the headless computer:  To install the Xsan file system and Xsan Admin app, enter: $ sudo installer -pkg /tmp/Install\ Xsan.mpkg -target /  To install only the Xsan Admin app, enter: $ sudo installer -pkg /tmp/Install\ Xsan.mpkg/Contents/Installers/ XsanAdminApp.pkg/ -target /  To monitor the installation, add the -verbose parameter: $ sudo installer -verbose -pkg /tmp/Install\ Xsan.mpkg -target /Appendix C Use command-line tools 145 Xsan commands Xsan includes these command-line tools: Tool Description cvadmin View or change volume and storage pool settings; see page 145 cvaffinity Manipulate affinity tags manually; see page 149 cvcp Copy files or folders; see page 149 cvfsck Check or repair a volume; see page 150 cvlabel View, label, and initialize LUNs; see page 151 cvmkdir Create a folder and assign an affinity; see page 152 cvmkfile Create and preallocate a file; see page 153 cvmkfs Initialize a volume; see page 153 cvupdatefs Apply volume setup changes; see page 154 snfsdefrag Defragment a volume; see page 154 xsanctl Mount and unmount Xsan volumes; see page 156 View or change volume and storage pool settings (cvadmin) Use the cvadmin tool to perform status and setup tasks related to Xsan volumes. For help, see the cvadmin man page or enter: $ sudo cvadmin -e help Enter interactive mode: $ sudo cvadmin Execute commands from a file: $ sudo cvadmin [-H host] [-F volume] -f cmdfile Execute a single command and return to the shell prompt: $ sudo cvadmin [-H host] [-F volume] -e ["]command [cmdparam..."]146 Appendix C Use command-line tools Parameter Description -H host The metadata controller that is hosting the volume. If not provided, the local computer is assumed. host – the IP address or DNS name of a metadata controller other than the one you’re logged in on. -F volume The volume to be the active (“selected”) volume in cvadmin. volume – the name of an Xsan volume -f cmdfile Read commands from the specified file. cmdfile – the name of a text file containing cvadmin commands -e command Execute the specified command and return to the shell prompt. Otherwise, cvadmin continues to run in interactive mode with the prompt Xsanadmin>. If you include parameters (cmdparam) with the command, enclose the command and its parameters in a pair of quotes. Available commands are listed in “cvadmin commands” below. cmdparam Values required by the command. cvadmin commands Commands available in the cvadmin tool are listed in the following table. cvadmin command Description activate [volume|index] Choose the active volume that you want to work with interactively. volume – the name of the volume index – the numeric ID of the volume (to see a list of these, use the cvadmin select command without any parameters) disks [refresh] List LUNs. down pool Disallow all access to a storage pool. pool – the name of a storage pool in the currently active volumeAppendix C Use command-line tools 147 cvadmin command Description fail (volume|index) Cause a volume to fail over to a standby controller. volume – the name of the volume index – the numeric ID of the volume (to see a list of these, use the cvadmin select command without any parameters) filelocks [yes|no] Enable or disable file and record locks. Use the command without any parameter to see the current setting for locks. multipath pool (rotate|static) Specify how Xsan uses multiple paths to a storage pool. pool – the name of a storage pool in the active volume paths List available LUNs. quit Exit from cvadmin. quotas [yes|no] Enable or disable quotas for the active (selected) volume. Use the command without parameters to see the current setting for quotas. quotas get (user|group) name Display current quota information for a user or group. name – the name of the user or group quotas set (user|group) name hard soft grace Set quotas for user or group name. name – the name of the user or group hard – hard quota (bytes) soft – soft quota (bytes) grace – grace period (minutes) quotacheck Recalculate quota information for the active volume.148 Appendix C Use command-line tools cvadmin command Description repquota Generate the following quota report files in / Library/Logs/Xsan/data/volume: quota_report.txt – text file quota_report.csv – comma-delimited file quota_regen.in – cvadmin commands that will set up identical quotas on another metadata controller. You can use cvadmin -f to execute the commands. repof Create a report of open files on the active volume in the file /Library/Logs/Xsan/data/volume/ open_file_report.txt. select [volume] Choose the active volume that you want to work with. The name of the active volume appears preceding the command prompt in interactive mode, for example: Xsanadmin (Vol1) > To see a list of running volumes, leave off the volume parameter. volume – the name of an Xsan volume show [pool] [long] List storage pool information for the active volume. pool – the name of a storage pool in the currently active volume start volume [on] [controller] Start a volume based on the information in its configuration file (/Library/Preferences/Xsan/ volume.cfg). volume – the name of an Xsan volume controller – The address of the metadata controller to start the volume’s FSM process on stat Display information about the active volume. stop volume Stop a volume and its FSM process on all metadata controllers. up pool Allow access to the specified storage pool. pool – the name of a storage pool in the currently active volume who Display client information for the active volume.Appendix C Use command-line tools 149 Manipulate affinity tags (cvaffinity) Use the cvaffinity command to assign an affinity tag to a folder or a file or to list the affinity tag assigned to a folder or a file. Assigning an affinity tag to a folder or file causes it to be stored on a storage pool that has the same affinity tag. You can see the affinity tags for available storage pools by using the show long command of the cvadmin tool. Set an affinity tag for a folder or file: $ cvaffinity -s affinity target List the affinity tag assigned to a folder or file: $ cvaffinity -l target Delete the affinity tag from a folder or file: $ cvaffinity -d target Parameter Description affinity The affinity tag that’s assigned to the storage pools where you want the target folder or file to be stored. target The path to and name of the folder or file. Copy files or folders (cvcp) Use the cvcp command to copy files or folders to or from an Xsan volume. $ cvcp [options] source destination Parameter Description options See “cvcp command options” below. source The file or folder (directory) to be copied. destination Where the copy is created. cvcp command options Option Description -A Turn off preallocation. -b buffers Set the number of I/O buffers to use. buffers – the number of buffers to use for the copy -k size Set the copy buffer size. size – the buffer size (bytes)150 Appendix C Use command-line tools Option Description -l Copy the targets of symbolic links, not the links. -n Do not apply the command to subfolders. -p prefix Only copy files with names that start with the specified prefix. prefix – characters to match with the beginning of the file name -s Allocate on storage pool block boundaries. -t Specify the number of copy threads. -v Report all information about the file copied. -x Retain original file permissions in the copy. -y Retain ownership and group information in the copy. This works only if the root user is performing the copy. -z Retain original modification times in the copy. Examples Copy the file friday to /datasets/data1/july/: $ cvcp friday /datasets/data1/july Copy the folder /data1/ and all subfolders to /datasets/data1/, retaining all permissions and ownerships and displaying files as they are copied: $ cvcp -vxy data1 /datasets/data1 Perform a similar copy as above, but only copy files with names that begin “jul”: $ cvcp -vxy -p jul data1 /datasets/data1/july Check or repair a volume (cvfsck) Use the cvfsck command to check or repair an Xsan volume. $ sudo cvfsck [options] volume Parameter Description options See “cvfsck command options” below. volume The name of the volume to check or repair.Appendix C Use command-line tools 151 cvfsck command options Option Description -d Display extra debugging information. -e Display file extents statistics. -f Report fragmentation. -g Print journal recovery log. -j Perform journal recovery. -J Display raw journal data. -K Reset journal. Warning: Resetting the journal might introduce metadata inconsistencies. Don’t use unless absolutely necessary. -l Record problems in the system log. -n Check volume in read-only mode. -r Relocate files before changing volume configuration. -v Display all available information. –w Modify the file system as needed to repair problems. -x Report statistics in comma-separated form for use in a spreadsheet. Label, list, and unlabel LUNs (cvlabel) Use the cvlabel command to initialize LUNs so they can be added to storage pools. For details, see the cvlabel man page. List available LUNs: $ sudo cvlabel -l [-s] [-v] Note: This command lists all disks, not just the available LUNs. List current LUN and label information you can paste into a label file: $ sudo cvlabel -c Note: This command lists all disks, not just the available LUNs.152 Appendix C Use command-line tools Label a LUN: $ sudo cvlabel [-v] [-f] [labelfile] Important: Be sure to use this command only on disks that aren’t being used. Using Xsan Admin to label LUNs is safer, because it only shows available LUNs. Remove the label from a LUN: $ sudo cvlabel -u lun Parameter Description -l List available LUNs. -s Display device serial numbers. -v Show progress display. -c Create a label template file. -f Relabels LUNs that are labeled. labelfile An optional file containing information for each label. You can use the -c option to create this file. lun The LUN identified by disk name—for example: /dev/disk4. -u Unlabel the specified LUN. Create a folder and assign an affinity (cvmkdir) Use the cvmkdir command to create a folder (directory) and assign it an affinity tag so that its contents are stored on storage pools with the same affinity tag. $ cvmkdir -k affinity folder Parameter Description -k affinity Specifies the affinity tag to be associated with the folder. affinity – the affinity tag that’s assigned to the storage pools where you want the folder’s contents to be stored You can use the show long command of the cvadmin tool to see a storage pool’s affinity tag. You can use -k "" to remove the folder’s affinity tag. folder The path to and name of the folder.Appendix C Use command-line tools 153 Create and preallocate a file (cvmkfile) Use the cvmkfile command to allocate space for a file on an Xsan volume. $ cvmkfile [-k affinity] [-p] [-s] [-w] [-z] size(k|m|g) filename Parameter Description -k affinity Allocate space for the file on one of the storage pools with the specified affinity tag. affinity – the affinity tag that’s assigned to the storage pools where you want the folder’s contents to be stored You can use the show long command of the cvadmin tool to see a storage pool’s affinity tag. -p Force future extensions of the file to be aligned on block boundaries. -s Force the file allocation to align with block boundaries. -w Set file size as indicated by size. -z Set the contents of the file to zeros. size(k|m|g) A number specifying the amount of space to allocate to the file. size – a number k – kilobytes m – megabytes g – gigabytes filename The path to and name of the file to allocate. Example Allocate 2 GB of space for the file “data1” on the storage pool “datasets”: $ cvmkfile -k datasets 2g data1 Initialize a volume (cvmkfs) Use the cvmkfs command to initialize an Xsan volume based on the information in the volume’s configuration (in /Library/Preferences/Xsan/volume.cfg). WARNING: Initializing a volume destroys all existing data on the volume. $ sudo cvmkfs [-G] [-F] [volume]154 Appendix C Use command-line tools Parameter Description -G Don’t display “Press return to continue” prompts. -F Don’t display warning and verification prompts. Use with caution. volume The name of the volume to initialize. This name matches the name of a configuration (.cfg) file in /Library/Preferences/Xsan/. Apply volume configuration changes (cvupdatefs) Use the cvupdatefs command to apply configuration file changes to a volume after you modify the volume’s configuration files. $ sudo cvupdatefs [-f] volume [configdir] Parameter Description -f Update without prompting for confirmation or advising of errors in the configuration file. volume The volume to update. If you don’t specify a volume, available volumes are listed for you to choose from. configdir Location of the volume’s configuration (.cfg) file if it’s not in the default location (/Library/ Preferences/Xsan/). Defragment a file, folder, or volume (snfsdefrag) Use the snfsdefrag command to defragment a file by reallocating its data in a single extent. This can improve read and write performance for a file by increasing disk efficiency and reducing file metadata management overhead. Defragment a file or folder: $ snfsdefrag [-D] [-d] [-q] [-s] [-v] [-K affinity] [-k affinity] [-m count] [-r] target Report file extents without defragmenting: $ snfsdefrag -e [-K affinity] [-r] target [target] [...] Display an extent count without defragmenting: $ snfsdefrag -c [-K affinity] [-r] target [target] [...] Prune a file (remove allocated extents beyond the end of file): $ snfsdefrag -p [-D] [-v] [-q] [-K affinity] [-m count] [-r] target [target] [...] List files that are candidates for defragmentation: $ snfsdefrag -l [-D] [-v] [-K affinity] [-m count] [-r] target [target] [...]Appendix C Use command-line tools 155 Parameter Description -c Display an extent count but don’t defragment target. -D Display debugging messages. -d Operate on files with other than the current depth. -e Report extents without defragmenting. -K affinity Only operate on files with the specified storage pool affinity. affinity – the affinity key (in Xsan, the affinity key is the same as the name of the storage pool) You can use the cvadmin show long command to see a storage pool’s affinity key. -k affinity Allocate new extents on the storage pool with this affinity. -l List files that might benefit from defragmentation. -m count Only operate on files with more than count extents. -p Prune instead of defragment. -q Suppress messages. -r [target] Operate recursively to defragment all files in all folders within the specified target folder. -s Allocate new extents on block boundaries. -v Display all available information and status during defragmentation. Examples Count the extents in the file datafile: $ snfsdefrag -c datafile List the extents: $ snfsdefrag -e datafile Defragment the file datafile: $ snfsdefrag datafile Defragment every file in the folder /datafolder/ (or any folder within /datafolder/) that has more than one extent: $ snfsdefrag -r datafolder Recover unused preallocated disk space assigned to every file in folder /datafolder/: $ snfsdefrag -rp datafolder156 Appendix C Use command-line tools Control the Xsan file system (xsanctl) Use the xsanctl command to control basic Xsan file system functions. For details, see the xsanctl man page. $ sudo xsanctl command xsanctl commands xsanctl command Description ping Sends a ping message to the Xsan file system to verify that it’s responding to management requests. mount volume [options] Mounts an Xsan volume on the computer. If successfully mounted, the volume will be automounted at startup. volume – the name of the volume options – a space-delimited list of options for the mount operation. Automatic remounts of this volume also use the given mount options. If no options are given, the options used for the last mount operation are used. Valid mount options are most of the mount options recognized by the mount_acfs command. The few mount_acfs mount options that don’t apply to Xsan are ignored. Options are given by name and prefaced by two dashes (--). For example, to disable atime updates, use the noatime option of mount_acfs like this: xsanctl mount --noatime For options that pass a parameter, the option name is followed by an equals sign (=) and then the option. For example, to specify that the kernel should create 12 threads for the mount point, use: xsanctl mount --threads=12 If you use the --at option, make sure it specifies a location in the root file system. Xsan volumes mounted atop other file systems may not automatically remount correctly. For more information about available options, see the mount_acfs man page. unmount volume Unmounts an Xsan volume on the computer. If successfully unmounted, the volume won’t be automounted at startup. volume – the name of the volumeAppendix C Use command-line tools 157 xsanctl command Description list Lists the volumes available on the SAN and the path at which each volume is mounted on the local computer. sanConfigChanged Notifies the Xsan file system that it should reload the SAN configuration. roleChanged Notifies the Xsan file system that this computer’s SAN role has changed or the computer was removed from the SAN. disksChanged Notifies the Xsan file system that it should rescan disks. wipeConfig Resets the Xsan file configuration to an unconfigured state. All files in /Library/ Preferences/Xsan/ are removed except uuid. The xsand process isn’t unloaded. Directory services aren’t reconfigured. Mount an Xsan volume Use the xsanctl command to mount an Xsan volume on a computer. Mount a volume from the command line: 1 Go to the computer and open Terminal, or use SSH to log in to the computer remotely: $ ssh user@computer Replace user with the name of a user account on the remote computer and computer with its IP address or DNS name. If you have trouble making an SSH connection, check the Sharing pane of System Preferences on the remote computer and make sure Remote Login service is turned on. 2 Mount the volume: $ sudo xsanctl mount volume For example: $ sudo xsanctl mount SanVol Unmount an Xsan volume Use the xsanctl command to unmount an Xsan volume on a computer. Unmount a volume: 1 Go to the computer and open Terminal, or use SSH to log in to the computer remotely: $ ssh user@computer Replace user with the name of a user account on the remote computer and computer with its IP address or DNS name.158 Appendix C Use command-line tools If you have trouble making an SSH connection, check the Sharing pane of System Preferences on the remote computer and make sure Remote Login service is turned on. 2 Unmount the volume: $ sudo xsanctl unmount volume For example: $ sudo xsanctl unmount SanVol View logs The system log to which Xsan writes information about SANs is in /var/log/system.log. Volume logs are in /Library/Logs/Xsan/data/volume/log/cvlog, where volume is the name of the specific volume. Xsan configuration files Xsan stores its configuration information in the following files. On Xsan metadata controllers and Xsan 2.3 clients (Macs with Mac OS X Lion or Lion Server), the configuration files are located at /Library/Preferences/Xsan/. Some of the following Xsan configuration files are present on Xsan 2.2 clients at /Library/Filesystems/Xsan/config/. Note: Don’t edit these files except under the direction of an Apple support engineer. File or folder in /Library/Preferences/Xsan/ Contents volume.cfg Volume settings volume-auxdata.plist Additional volume settings used by Xsan Admin fsmlist Volume autostart list fsnameservers Controller list automount.plist Xsan volumes to be mounted during startup, and their mount options config.plist Private Xsan Admin configuration information notifications.plist Notification settings made with Xsan Admin notes/ Note files whose contents were entered in Xsan Admin’s Inspector window uuid Private Xsan Admin computer identification information license.dat StorNext license information159 affinity A relationship between a folder on an Xsan volume and one or more storage pools that provide storage for the volume. The affinity guarantees that files placed in the folder are stored only on the associated storage pools. Storage pools can differ in capacity and performance, and affinities can be used to assure that data such as video, which requires high transfer speed, is stored on the fastest storage devices. affinity tag In Xsan predefined volume types, you assign LUNs to affinity tags instead of assigning the LUNs directly to storage pools. Then Xsan Admin can create underlying storage pools with appropriate affinities and the optimal numbers of LUNs to achieve best performance. allocation strategy In Xsan, the order in which data is written to the storage pools that make up a volume. Applicable only if there’s more than one storage pool in a volume, and only if the pools are of the same class. Can be fill, round robin, or balance. balance An Xsan storage pool allocation strategy. Before allocating space on a volume consisting of more than one storage pool, Xsan checks available storage on all pools, and then uses the one with the most free space. block allocation size An Xsan volume property. The smallest number of bytes that can be reserved on, written to, or read from an Xsan volume. client A computer (or a user of the computer) that requests data or services from another computer, or server. controller In an Xsan storage area network, short for metadata controller. In RAID systems, controller refers to hardware that manages the reading and writing of data. By segmenting and writing or reading data on multiple drives simultaneously, the RAID controller achieves fast and highly efficient storage and access. See also metadata controller. failover In Xsan, the automatic process by which a standby metadata controller becomes the active metadata controller if the primary controller fails. failover priority On a SAN with more than one controller, specifies which standby controller to try first during failover. file system A scheme for storing data on storage devices that allows apps to read and write files without having to deal with lower-level details. Glossary Glossary160 Glossary file system server See FSS. fill An Xsan storage pool allocation strategy. In a volume consisting of more than one storage pool, Xsan fills up the first pool before writing to the next. format (verb) In general, to prepare a disk for use by a particular file system. FSS File system server. The StorNext File System term for the computer that manages metadata in a storage area network (SAN). In Xsan, this is called a metadata controller. initialize To prepare a disk for use by a particular file system. In Xsan, to prepare a RAID array for use in a storage pool. label (noun) In Xsan, an identifying name for a LUN. You can assign a label to a LUN before or during setup of an Xsan storage pool. label (verb) Used by some sources (such as StorNext) to refer to the process of preparing a logical disk for use with a file system. In Xsan, however, initialize is used to refer to preparing a disk for use in a storage pool. logical disk A storage device that appears to a user as a single disk for storing files, even though it might actually consist of more than one physical disk drive. An Xsan volume, for example, is a logical disk that behaves like a single disk even though it consists of multiple storage pools that are, in turn, made up of multiple LUNs, each of which contains multiple disk drives. See also physical disk. LUN Logical unit number. A SCSI identifier for a logical storage device. In Xsan, an unformatted logical storage device such as a RAID array or slice. metadata Information about a file system and the files it stores (for example, which disk blocks a file occupies or which blocks are available for use). In Xsan, metadata is managed by a metadata controller and exchanged over an Ethernet connection, while actual file data is transferred over a Fibre Channel connection. metadata controller The computer that manages metadata in an Xsan storage area network. mount (verb) To make a remote directory or volume available for access on a local system. In Xsan, to cause an Xsan volume to appear on a client’s desktop, just like a local disk. physical disk An actual, mechanical disk. Compare with logical disk. RAID Redundant Array of Independent (or Inexpensive) Disks. A grouping of multiple physical hard disks into a disk array, which either provides high-speed access to stored data, mirrors the data so that it can be rebuilt in case of disk failure, or both. The RAID array is presented to the storage system as a single logical storage unit. See also RAID array, RAID level. RAID 0 A RAID scheme in which data is distributed evenly in stripes across an array of drives. RAID 0 increases the speed of data transfer, but provides no data protection.Glossary 161 RAID 0+1 A combination of RAID 0 and RAID 1. This RAID scheme is created by striping data across multiple pairs of mirrored drives. RAID 1 A RAID scheme that creates a pair of mirrored drives with identical copies of the same data. It provides a high level of data availability. RAID 3 A RAID scheme that stripes data across two or more drives and stores parity data on a dedicated drive. In the event of a disk failure, the redundant parity bits can be used to reconstruct data on any drive. RAID 5 A RAID scheme that distributes both data and parity information across an array of drives one block at a time, with each drive operating independently. This enables maximum read performance when accessing large files. RAID array A group of physical disks organized and protected by a RAID scheme and presented by RAID hardware or software as a single logical disk. In Xsan, RAID arrays appear as LUNs, which are combined to form storage pools. RAID level A storage allocation scheme used for storing data on a RAID array. Specified by a number, as in RAID 3 or RAID 0+1. RAID set See RAID array. round robin An Xsan storage pool allocation strategy. In a volume consisting of more than one storage pool, Xsan allocates space for successive writes to each available pool in turn. SAN Storage area network. In general, a network whose primary purpose is the transfer of data between computer systems and storage elements and among storage elements. In Xsan, a SAN is a combination or one or more controllers, storage volumes, and storage clients. storage pool A group of logical disks that share common characteristics, such as throughput or latency, across which user data is striped. In Xsan, storage pools are combined into volumes. The StorNext File System calls this a stripe group. stripe (verb) To write data to successive stripes in a RAID array or LUN. stripe breadth An Xsan storage pool property. The number of bytes of data, expressed as a number of file system blocks, that Xsan writes to a LUN in a storage pool before moving to the next LUN in the pool. stripe group The StorNext File System term for an Xsan storage pool. volume A mountable allocation of storage that behaves, from the client’s perspective, like a local hard disk, hard disk partition, or network volume. In Xsan, a volume consists of one or more storage pools. See also logical disk.A access permissions for folders 97 unmounting a volume 98 access control list. See ACLs ACLs enabling and disabling 82 setting up in Xsan Admin 97 Active Directory 58, 61 adding clients to SAN 89 adding storage 38, 71 affinity assigning to folder 77 described 35, 36 removing 79 affinity tag 35 allocation strategy setting for volume 80 availability considerations 47 B balance volume allocation strategy 80 block allocation size choosing for a volume 80 C case sensitivity 66, 82, 90 client worker threads 93 clients adding 89 adding serial number 91 checking quotas from 104 defined 33 moving 91 removing from SAN 99 StorNext 141 using a volume 121 command-line tools cvadmin 145 cvaffinity 149 cvcp 149 cvfsck 150 cvlabel 151 cvmkdir 152 cvmkfile 153 cvmkfs 153 cvupdatefs 154 installed location 142 man pages 143 snfsdefrag 154 xsanctl 156 compatibility with other versions of Xsan 13 configuration files 158 controllers adding 107 changing IP address 111 limit per SAN 38 listing hosted volumes 110 overview 33 cvadmin tool 145 cvaffinity tool 149 cvcp tool 149 cvfsck tool 150 checking volumes 85, 86 repairing volumes 87 cvlabel tool 151 cvmkdir tool 152 cvmkfile tool 153 cvmkfs tool 153 cvupdatefs tool 154 D defragmenting volumes 85 delay access time updates 93 directory cache size 93 directory services 43, 57, 61 Directory Utility 62 E email notifications 119 enabling Xsan 63 Ethernet configuring 59 guidelines 42 Index 162 IndexIndex 163 exclusive affinity tag 84 expanding storage 38, 71 extended attributes enabling 81 F failover 109 forcing 109 failover priority 109 Fibre Channel configuration requirements 41 monitoring connection failures 120 supported switches 41 file systems. See volumes files limit per volume 38 maximum size 38 name length limit 38 fill volume allocation strategy 80 firewall, and Xsan Admin 58 fragmentation 85 free space checking quota use 103 checking storage pool 117 checking volume 117 G grace period (quota) 102 graphs controller overall CPU use 118 controller overall IP network use 118 group ID. See GID groups configuring 61 setting up 57 H hard quota checking 103 defined 102 setting 100 home folders creating local 44, 96 I IP addresses changing for controller 111 J journal choosing location 50 described 37 L logical unit number. See LUNs logs controlling number of messages 58 viewing 120 LUNs (logical unit numbers) actual size vs. used size 76, 123 adding to existing affinity tag 75 description 34 limit per storage pool 38 limit per volume 38 maximum size 38 name length limit 38 overview 33 preparing 56, 72 setup scripts 72 size adjusted downward 123, 125 trouble adding to storage pool 125 M mail service for notifications 44 man pages for command-line tools 143 memory requirements 40 metadata choosing location 50 described 37 estimating space requirement 51 mount options 93 mounting a volume 92 from the command line 157 moving clients to another SAN 91 N naming limits 38 networks in SAN overview 32, 33 notation conventions for commands 143 notifications mail service required 44 setting up 68, 119 O Open Directory 57, 61 P permissions user access to folders 97 Q quotas checking from client 104164 Index checking from command line 104 checking usage in Xsan Admin 103 described 102 example 103 grace period 102 setting 68, 100 R RAID schemes for LUNs 47 refresh interval, Xsan Admin 58 repairing a volume 87 round robin volume allocation strategy 80 S SAN (storage area network) adding 69 adding clients 89 adding storage 71 destroying 70 managing multiple 69 moving clients 91 name length limit 38 renaming 69 security considerations 38, 47 serial number adding 91 server setup assistant 57 shared secret file 141 shell commands. See command-line tools. snfsdefrag tool 154 defragmenting files 86 soft quota checking 103 defined 102 setting 100 Spotlight enabling and disabling 66, 81 storage area network. See SAN storage pools adding to existing volume 74 advanced settings 83 checking free space 117 described 35 limit per volume 38 name length limit 38 reserved names 124 storage, expanding 71 StorNext File System 140 stripe breadth 84 stripe groups. See storage pools striping, across LUNs 35, 37 system requirements 40 T text message notifications 119 time server 60 tools. See command-line tools. troubleshooting can’t access RAID system 123 can’t connect to SAN 122 can’t enable Xsan 122 can’t mount volume 123 can’t unmount volume 123 client unable to reconnect 124 computers not listed 122 file copy doesn't finish 125 LUN size adjusted downward 123, 125 poor Fibre Channel performance 124 reserved storage pool names 124 unable to add LUN 125 unable to rename volume 123 volume restarts 126 U unmounting a volume 98 from the command line 157 users configuring 61 finding 58 home folders 57 setting up 57 V volume configuration file 158 volumes adding to existing SAN 73 checking free space 117 checking integrity 86 configuration file 158 defragmenting 85 described 36 destroying 88 fragmentation 85 identifying controller 110 listed by controller 110 mounting from command line 157 name length limit 38 repairing 87 show clients using 121 trouble mounting 123 unmounting 98, 157 X Xsan Admin installing 68 remote SAN management 69 Xsan Admin application and firewalls 58Index 165 overview 58 preferences 58 refresh interval 58 Xsan software disabling 99 version compatibility 13 Xsan enabling 63 xsanctl tool 156 Let’s get started When you start your MacBook Pro for the first time, Setup Assistant will help you get going. Just follow a few simple steps to quickly connect to your Wi-Fi network, transfer your stuff from another Mac or a PC, and create a user account for your Mac. You’ll also be able to log in with your Apple ID. This will allow you to shop the App Store, iTunes Store, and Apple Online Store. It will let you keep in touch using Messages and FaceTime. And it will let you access iCloud, which is automatically set up on your Mac in apps like Mail, Contacts, and Calendar. If you don’t have an Apple ID, you can create one in Setup Assistant. Multi-Touch gestures You can do a lot of things on your MacBook Pro using simple gestures on the trackpad. Here are some of the most popular ones. Get to know your desktop The desktop is where you can find everything and do anything on your Mac. The Dock at the bottom of the screen is a handy place to keep the apps you use most. It’s also where you can open System Preferences, which lets you customize your desktop and other settings on your Mac. Click the Finder icon to quickly get to all your files and folders. The menu bar at the top has lots of useful information about your Mac. To check the status of your wireless Internet connection, click the Wi-Fi icon. Your Mac automatically connects to the network you chose during setup. Hello. Multi-Touch trackpad MagSafe 2 power connector Power adapter AC power cord Power button Click Press down anywhere on the trackpad to click. Or, with Tap to Click enabled, simply tap the surface. Secondary click (right click) Click with two fingers to open shortcut menus. Or, with Tap to Click enabled, tap two fingers anywhere. Swipe to navigate Swipe with two fingers to flip through web pages, documents, and more. Double click Press down two times anywhere on the trackpad. Or, with Tap to Click enabled, double-tap the surface. Two-finger scroll Brush two fingers along the trackpad to scroll in any direction—up, down, or sideways. Smart zoom Double-tap the trackpad with two fingers to quickly magnify a web page. Pinch to zoom Zoom in and out of photos and web pages more precisely by pinching your thumb and finger. Switch between full-screen apps Swipe with three fingers to move from one full-screen app to another. View Launchpad Pinch with four fingers to view all your apps in Launchpad. Rotate Turn your thumb and finger clockwise or counterclockwise to rotate an image. View Mission Control Swipe up with three fingers to see every open window on your Mac. Learn more Choose System Preferences from the Apple menu and click Trackpad to learn more about gestures. iCloud iCloud stores your music, photos, documents, calendars, and more. And it wirelessly pushes them to your Mac, iPhone, iPad, iPod touch, and even your PC. All without docking or syncing. So when you buy a song on one device, it’s instantly available on all your other devices. When you adjust your calendar, all your devices stay up to date. And with Photo Stream, your latest photos appear everywhere you want to see them, automatically. To customize your iCloud settings, open the Apple menu, choose System Preferences, and click iCloud. Then sign in with your Apple ID and choose the iCloud features you want to use. An important note Please read this document and the safety information in the Important Product Information Guide carefully before you first use your computer. Learn more You can find more information, watch demos, and learn even more about MacBook Pro features at www.apple.com/macbookpro. Help You can often find answers to your questions, as well as instructions and troubleshooting information, in Help Center. Click the Finder icon, click Help in the menu bar, and choose Help Center. OS X Utilities If you have a problem with your Mac, OS X Utilities can help you repair your computer’s flash storage, restore your software and data from a Time Machine backup, or erase your flash storage and reinstall OS X and Apple applications. You can also use Safari to get online help. If your Mac detects a problem, it opens OS X Utilities automatically. Or you can open it manually by restarting your computer while holding down the Command and R keys. Support Your MacBook Pro comes with 90 days of technical support and one year of hardware repair warranty coverage at an Apple Retail Store or an Apple Authorized Service Provider. Visit www.apple.com/support/macbookpro for MacBook Pro technical support. Or call 1-800-275-2273. In Canada, call 1-800-263-3394. Not all features are available in all areas. TM and © 2012 Apple Inc. All rights reserved. Designed by Apple in California. Printed in XXXX. 034-6357-A AC plug Help menu Menu bar Finder Dock System Preferences Quick Start Guide Let’s get moving It’s easy to move files like documents, email, photos, music, and movies to your new Mac from another Mac or a PC. The first time you start your new Mac, it will walk you through the process step by step. All you have to do is follow the onscreen instructions. Welcome to your new MacBook Pro. We’d like to show you around. MagSafe 2 USB 3 Headphone FaceTime HD camera SDXC HDMI USB 3 Wi-Fi status Thunderbolt Dual microphonesClick the Safari icon in the Dock and surf the web quickly and easily with Multi-Touch gestures. Scroll up or down with two fingers on the trackpad. Swipe right and left with two fingers to go back and forth Safari web browser Mail Top Sites Get a quick overview of the sites you visit most often. One-stop email View all your accounts in Mail for one-click access. Conversation view See all the email messages from a conversation thread. Search Quickly narrow search results to find exactly what you want. Mail lets you manage all your email accounts from a single, ad-free inbox, even when you’re not connected to the Internet. It works with most email standards— including POP3 and IMAP—and between pages. Double-tap with two fingers to magnify a page, then double-tap again to return to the original size. Or pinch to zoom in and out. popular email services like Gmail, Yahoo! Mail, and AOL Mail. You can also use Mail for the free me.com email account you get with iCloud. The first time you open Mail, Setup Assistant will help you get started. Launchpad Open Launchpad Click the Launchpad icon in the Dock. Folders Group apps in folders by dragging one app on top of another. Launchpad is the home for all the apps on your Mac. Just click the Launchpad icon in the Dock, and your open windows are replaced by a full-screen display of all your apps. Arrange apps any way you want, group them together in folders, or delete them from your Mac. When you download an app from the Mac App Store, it automatically appears in Launchpad. Mission Control Mission Control gives you a bird’s-eye view of everything running on your Mac. Click the Mission Control icon in the Dock, and your desktop zooms out to display all the open windows in every application, all your fullscreen apps, and Dashboard, the home of mini-apps called widgets. Click anything to zoom in on it. Think of Mission Control as the hub of your system—view everything and go anywhere with just a click. Open Mission Control Click the Mission Control icon in the Dock. Add desktop spaces Click the + button to the right of the top row to add a new space. Dashboard Located at the top left for easy access. Reading List Click the glasses icon to save pages to read later. Mac App Store The Mac App Store is the best way to find and download thousands of apps for your Mac, from games and social networking to productivity apps and more. New apps install in one step to Launchpad. You can install apps on every Mac authorized for your personal use and even download them again. The Mac App Store lets you know when app and OS X updates are available, so you always have the latest versions. Open the Mac App Store by clicking its icon in the Dock. iTunes With iTunes, you can organize and play your digital music and videos on your Mac. And you can shop in the iTunes Store for new music, movies, TV shows, books, and more. iTunes is also where you’ll find the App Store for iPad, iPhone, and iPod touch. iTunes Store Discover and buy new music, movies, and more. Genius Mixes Let iTunes search your music library and group songs that go great together. Calendar Multiple calendars Access all your calendars from one place. Keep track of your busy schedule with Calendar. You can create separate calendars—one for home, another for school, a third for work. See all your calendars in a single window or choose to see only the calendars you want. Create and send invitations using contact info from the Contacts app, then see who has responded. Use iCloud to update calendars on all your devices automatically or share calendars with other iCloud users. iPhoto Create Create books, cards, and calendars. Faces iPhoto can even organize your photos based on who’s in them. Events Double-click any Event to browse photos. iPhoto is the best way to organize, browse, edit, and share your photos on your Mac. You can organize your photo library by Faces, Places, and Events. To send photos by email or publish them to Facebook, just select the photo and click Share in the bottom right of your screen. Or click Create to turn your favorite shots into photo books, calendars, and cards. iMovie Event browser Your imported videos appear here so you can access all your clips. Project browser Simply drop your clips in a project to create a great movie. iMovie puts all your video clips in one place and gives you the editing tools and special effects you need to quickly turn them into something memorable. You can make great-looking movies or even Hollywood-style movie trailers with just a few clicks. And iMovie lets you import video from most popular digital video cameras, your iPhone, iPad, or iPod touch, or the FaceTime HD camera on your Mac. Messages Just log in with your Apple ID, and you can send unlimited messages including text, photos, videos, and more to your friends on a Mac, iPad, iPhone, or iPod touch. With iCloud, you can start a conversation on one device and pick it up on another. And if you want to talk to someone face to face, you can start a video call* just by clicking the FaceTime icon in the top-right corner of the Messages window. Replies in progress Three dots mean your friend is typing a reply. Delivery receipts See when your message has arrived. FaceTime Start a video call right in Messages. *Requires FaceTime-enabled device for both caller and recipient. Not available in all areas. Full-screen view Click the full-screen button to go full screen. Always up to date Updates to your purchased apps and OS X appear automatically. Discover new apps Browse thousands of apps and download them straight to Launchpad. Calendar view Select the view you prefer—day, week, month, or year. Add an event Double-click in a calendar to create a new event. Cocoa Drawing GuideContents Introduction to Cocoa Drawing Guide 10 At a Glance 10 See Also 11 Overview of Cocoa Drawing 12 Cocoa Drawing Support 12 The Painter’s Model 13 The Drawing Environment 14 The Graphics Context 14 The Graphics State 15 The Coordinate System 16 Transforms 16 Color and Color Spaces 17 Basic Drawing Elements 17 Geometry Support 17 Shape Primitives 18 Images 19 Gradients 20 Text 20 Views and Drawing 21 Common Drawing Tasks 22 Graphics Contexts 24 Graphics Context Basics 24 The Current Context 25 Graphics State Information 27 Screen Canvases and Print Canvases 29 Graphics Contexts and Quartz 30 Modifying the Current Graphics State 30 Setting Colors and Patterns 31 Setting Path Attributes 31 Setting Text Attributes 32 Setting Compositing Options 32 Setting the Clipping Region 35 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 2Setting the Anti-aliasing Options 37 Creating Graphics Contexts 38 Creating a Screen-Based Context 39 Creating a PDF or PostScript Context 39 Threading and Graphics Contexts 40 Coordinate Systems and Transforms 41 Coordinate Systems Basics 41 Local Coordinate Systems 41 Points Versus Pixels 43 Resolution-Independent User Interface 44 Transform Basics 45 The Identity Transform 45 Transformation Operations 46 Transformation Ordering 48 Transform Mathematics 50 Using Transforms in Your Code 51 Creating and Applying a Transform 51 Undoing a Transformation 52 Transforming Coordinates 53 Converting from Window to View Coordinates 53 Flipped Coordinate Systems 55 Configuring Your View to Use Flipped Coordinates 56 Drawing Content in a Flipped Coordinate System 56 Creating a Flip Transform 59 Cocoa Use of Flipped Coordinates 60 Doing Pixel-Exact Drawing 61 Tips for Resolution Independent Drawing in Cocoa 62 Accessing the Current Scale Factor 62 Adjusting the Layout of Your Content 63 Converting Coordinate Values 64 Color and Transparency 65 About Color and Transparency 65 Color Models and Color Spaces 65 Color Objects 66 Color Component Values 66 Transparency 66 Pattern Colors 67 Color Lists 68 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 3 ContentsColor Matching 68 Creating Colors 68 Working with Colors 69 Applying Colors to Drawn Content 69 Applying Color to Text 70 Getting the Components of a Color 70 Choosing Colors 71 Working with Color Spaces 71 Converting Between Color Spaces 71 Mapping Physical Colors to a Color Space 72 Images 74 Image Basics 75 Image Representations 75 Images and Caching 77 Image Size and Resolution 80 Image Coordinate Systems 81 Drawing Versus Compositing 82 Supported Image File Formats 83 Basic Formats 83 TIFF Compression 84 Support for Other File Formats 84 Guidelines for Using Images 86 Creating NSImage Objects 87 Loading an Existing Image 87 Loading a Named Image 87 Drawing to an Image by Locking Focus 88 Drawing Offscreen Images Using a Block-Based Drawing Method to Support High Resolution Displays 89 Creating a Bitmap 89 Creating a PDF or EPS Image Representation 93 Using a Quartz Image to Create an NSImage 95 Working with Images 95 Drawing Images into a View 95 Drawing Resizable Textures Using Images 96 Creating an OpenGL Texture 98 Applying Core Image Filters 100 Getting and Setting Bitmap Properties 100 Converting a Bitmap to a Different Format 100 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 4 ContentsAssociating a Custom Color Profile With an Image 101 Converting Between Color Spaces 102 Premultiplying Alpha Values for Bitmaps 108 Creating New Image Representation Classes 109 Advanced Drawing Techniques 111 Adding Shadows to Drawn Paths 111 Creating Gradient Fills 113 Using the NSGradient Class 114 Using Quartz Shadings in Cocoa 118 Drawing to the Screen 119 Capturing the Screen 119 Full-Screen Drawing in OpenGL 120 Full-Screen Drawing in Cocoa 121 Disabling Screen Updates 124 Using NSTimer for Animated Content 124 Using Cocoa Animation Objects 125 Optimizing Your Drawing Code 125 Draw Minimally 125 Avoid Forcing Synchronous Updates 125 Reuse Your Objects 126 Minimize State Changes 126 Text 127 Text Attributes 127 Simple Text Drawing 128 Advanced Text Drawing 128 Paths 130 Path Building Blocks 130 The NSBezierPath Class 131 Path Elements 131 Subpaths 133 Path Attributes 133 Winding Rules 141 Manipulating Geometric Types 142 Drawing Fundamental Shapes 144 Adding Points 144 Adding Lines and Polygons 145 Adding Rectangles 146 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 5 ContentsAdding Rounded Rectangles 146 Adding Ovals and Circles 147 Adding Arcs 148 Adding Bezier Curves 151 Adding Text 151 Drawing the Shapes in a Path 152 Drawing Rectangles 152 Working with Paths 154 Building Paths 154 Improving Rendering Performance 154 Manipulating Individual Path Elements 156 Transforming a Path 157 Creating a CGPathRef From an NSBezierPath Object 157 Detecting Mouse Hits on a Path 160 Incorporating Other Drawing Technologies 162 Using Quartz in Your Application 162 Using Quartz Features 162 Graphics Type Conversions 163 Getting a Quartz Graphics Context 164 Creating a Cocoa Graphics Context Using Quartz 165 Modifying the Graphics State 165 Using OpenGL in Your Application 165 Using NSOpenGLView 165 Creating an OpenGL Graphics Context 166 Using QuickTime in Your Application 167 Using the QuickTime Kit 168 Using QuickTime C-Based Functions 168 Using Quartz Composer Compositions 168 Choosing the Right Imaging Technology 169 Document Revision History 170 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 6 ContentsFigures, Tables, and Listings Overview of Cocoa Drawing 12 Figure 1-1 The painter’s model 14 Figure 1-2 Examples of shape primitives 18 Figure 1-3 Examples of bitmap images 19 Figure 1-4 Examples of text 20 Table 1-1 Primitive data types 17 Table 1-2 Common tasks and solutions 22 Graphics Contexts 24 Figure 2-1 Compositing operations in Cocoa 33 Figure 2-2 Clipping paths and winding rules 36 Figure 2-3 A comparison of aliased and anti-aliased content 38 Table 2-1 Graphics state information 27 Table 2-2 Mathematical equations for compositing colors 34 Coordinate Systems and Transforms 41 Figure 3-1 Screen, window, and view coordinate systems on the screen 42 Figure 3-2 Translating content 46 Figure 3-3 Scaling content 47 Figure 3-4 Rotated content 48 Figure 3-5 Transform ordering 49 Figure 3-6 Basic transformation matrix 50 Figure 3-7 Mathematical conversion of coordinates 50 Figure 3-8 Normal and flipped coordinate axes 55 Figure 3-9 Compositing an image to a flipped view 58 Listing 3-1 Flipping the coordinate system manually 60 Color and Transparency 65 Figure 4-1 Drawing with a pattern 67 Table 4-1 Methods for changing color attributes 69 Table 4-2 Quartz rendering intents 72 Images 74 Figure 5-1 Image orientation in an unflipped view 82 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 7Figure 5-2 Drawing a three-part image 97 Figure 5-3 Drawing a nine-part image 97 Table 5-1 Image representation classes 76 Table 5-2 Image caching modes 78 Table 5-3 Implied cache settings 78 Table 5-4 Image interpolation constants 80 Table 5-5 Cocoa supported file formats 83 Table 5-6 TIFF compression settings 84 Table 5-7 Additional formats supported by Cocoa 85 Listing 5-1 Drawing to an image 88 Listing 5-2 Capturing the contents of an existing image 91 Listing 5-3 Drawing to an offscreen window 92 Listing 5-4 Drawing directly to a bitmap 93 Listing 5-5 Creating PDF data from a view 94 Listing 5-6 Creating an OpenGL texture from an image 98 Listing 5-7 Adding a ColorSync profile to an image 101 Listing 5-8 Creating a bitmap with a custom color profile 102 Listing 5-9 Converting a bitmap to a different color space 104 Listing 5-10 Using a CGImageRef object to create an NSImage object 106 Listing 5-11 Creating a color space from a custom color profile 107 Advanced Drawing Techniques 111 Figure 6-1 Shadows cast by rendered paths 111 Figure 6-2 Different types of gradients 114 Figure 6-3 Axial gradient drawn inside a Bezier path 117 Figure 6-4 Gradient created using primitive drawing method 118 Listing 6-1 Adding a shadow to a path 112 Listing 6-2 Clipping an axial gradient to a rounded rectangle 116 Listing 6-3 Drawing a radial gradient using primitive routine 117 Listing 6-4 Creating an OpenGL full-screen context 120 Listing 6-5 Creating a Cocoa full-screen context 122 Paths 130 Figure 8-1 Path elements for a complex path 132 Figure 8-2 Line cap styles 135 Figure 8-3 Line join styles 136 Figure 8-4 Line dash patterns 137 Figure 8-5 Flatness effects on curves 138 Figure 8-6 Miter limit effects 140 Figure 8-7 Applying winding rules to a path 142 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 8 Figures, Tables, and ListingsFigure 8-8 Inscribing the corner of a rounded rectangle 147 Figure 8-9 Creating arcs 149 Figure 8-10 Cubic Bezier curve 151 Figure 8-11 Stroking and filling a path. 152 Table 8-1 Path element commands 131 Table 8-2 Winding rules 141 Table 8-3 Commonly used geometry functions 143 Table 8-4 Rectangle frame and fill functions 153 Listing 8-1 Creating a complex path 133 Listing 8-2 Setting the line width of a path 134 Listing 8-3 Setting the line cap style of a path 136 Listing 8-4 Setting the line join style of a path 137 Listing 8-5 Adding a dash style to a path 137 Listing 8-6 Setting the flatness of a path 139 Listing 8-7 Setting the miter limit for a path 140 Listing 8-8 Drawing a point 144 Listing 8-9 Using lines to draw a polygon 145 Listing 8-10 Drawing a rectangle 146 Listing 8-11 Drawing a rounded rectangle 147 Listing 8-12 Creating three arcs 149 Listing 8-13 Changing the control point of a curve path element 156 Listing 8-14 Creating a CGPathRef from an NSBezierPath 158 Listing 8-15 Detecting hits on a path 160 Incorporating Other Drawing Technologies 162 Table 9-1 Simple data-type conversions 163 Table 9-2 Equivalent Cocoa and Quartz data types 163 Table 9-3 Imaging technologies 169 Listing 9-1 Creating an OpenGL graphics context 166 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 9 Figures, Tables, and ListingsHigh-quality graphics are an important part of a well-designed application. In fact, high-quality graphicsis one of the things that sets OS X apart from many other operating systems. While some operating systems rely on flat colors and rectangular objects, OS X uses color, transparency, and its advanced compositing system to give programs a more fluid and inviting appearance. At a Glance This document isintended for developers who are new to drawing custom content using Cocoa. More advanced Cocoa developers may also want to read this book for tips on how to perform specific tasks. Before you begin reading this document, you should be familiar with the basic concepts of how to create a Cocoa application. This includes how to create new projects in Xcode, how to create a simple nib file, and how to manipulate Cocoa objects. You do not need any understanding of graphics programming in general, although such knowledge definitely helps. This document assumesthat you have read Cocoa Fundamentals Guide and are familiar with the basic concepts for creating a Cocoa application. This book also assumesthat you have a basic understanding of the Objective-C programming language. This document has the following chapters: ● “Overview of Cocoa Drawing” (page 12) introduces drawing-related concepts and the Cocoa support for drawing. ● “Graphics Contexts” (page 24) describes the drawing environment and provides examples of how you configure the environment to suit your needs. ● “Coordinate Systems and Transforms” (page 41) describes the coordinate systems used for drawing and provides examples of how you manipulate your content using transforms. ● “Color and Transparency” (page 65) provides basic information about color and shows you how to use the color-related Cocoa objects. ● “Paths” (page 130) describes the basic drawing tools found in Cocoa and provides detailed information about how to create and manipulate everything from simple shapes to Bezier paths. ● “Images” (page 74) describes the image classes found in Cocoa and provides examples of how to create and manipulate images in your application. 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 10 Introduction to Cocoa Drawing Guide● “Text” (page 127) provides an overview of text and its relationship to the Cocoa drawing environment. ● “Advanced Drawing Techniques” (page 111) demonstrates some advanced drawing-related techniques, including full-screen drawing, animation, gradients, and performance tuning. ● “Incorporating Other Drawing Technologies” (page 162) provides information and examples on how to integrate advanced technologies, such as Quartz, OpenGL, and QuickTime, into your Cocoa application. See Also Drawing is only one step in the process of creating a fully functional Cocoa view. Understanding view hierarchies and how events interact with views are two other critical steps. For information about these other subjects, consult the following documents: ● View Programming Guide—for information about creating and managing views ● Cocoa Event Handling Guide—for information about event handling To ensure the drawing in your app looks great on a Retina display, consult this document: ● High Resolution Guidelines for OS X Because Cocoa drawing is based on Quartz, many Quartz behaviors (though not all) are also relevant to Cocoa. This document describes the different behaviors provided by Cocoa, but for additional information about Quartz behavior, consult the following documents: ● Quartz 2D Programming Guide—for conceptual information related to Quartz. Introduction to Cocoa Drawing Guide See Also 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 11Drawing is a fundamental part of most Cocoa applications. If your application uses only standard system controls, then Cocoa does all of the drawing for you. If you use custom views or controls, though, then it is up to you to create their appearance using drawing commands. The following sections provide a quick tour of the drawing-related features available in Cocoa. Subsequent chapters provide more details about each feature, and also include examples for many common tasks you might perform during drawing. Cocoa Drawing Support The Cocoa drawing environment is available to all applications built on top of the Application Kit framework (AppKit.framework). This framework defines numerous classes and functions for drawing everything from primitive shapes to complex images and text. Cocoa drawing also relies on some primitive data types found in the Foundation framework (Foundation.framework). The Cocoa drawing environment is compatible with all of the other drawing technologies in OS X, including Quartz, OpenGL, Core Image, Core Video, Quartz Composer, PDF Kit, and QuickTime. In fact, most Cocoa classes use Quartz extensively in their implementations to do the actual drawing. In cases where you find Cocoa does not have the features you need, it is no problem to integrate other technologies where necessary to achieve the desired effects. Because it is based on Quartz, the Application Kit framework provides most of the same features found in Quartz, but in an object-oriented wrapper. Among the features supported directly by the Application Kit are the following: ● Path-based drawing (also known as vector-based drawing) ● Image creation, loading and display ● Text layout and display ● PDF creation and display ● Transparency ● Shadows ● Color management 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 12 Overview of Cocoa Drawing● Transforms ● Printing support ● Anti-aliased rendering ● OpenGL support Like Quartz, the Cocoa drawing environment takes advantage of graphics hardware wherever possible to accelerate drawing operations. This support is automatic. You do not have to enable it explicitly in your code. For information about the classes available in Cocoa, see Application Kit Framework Reference and Foundation Framework Reference . For information on how to integrate C-based technologies into your Cocoa application, see “Incorporating Other Drawing Technologies” (page 162). The Painter’s Model Like Quartz, Cocoa drawing uses the painter’s model for imaging. In the painter’s model, each successive drawing operation applies a layer of “paint” to an output “canvas.” As new layers of paint are added, previously painted elements may be obscured (either partially or totally) or modified by the new paint. This model allows you to construct extremely sophisticated images from a small number of powerful primitives. Overview of Cocoa Drawing The Painter’s Model 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 13Figure 1-1 shows how the painter’s model works and demonstrates how important drawing order can be when rendering content. In the first result, the wireframe shape on the left is drawn first, followed by the solid shape, obscuring all but the perimeter of the wireframe shape. When the shapes are drawn in the opposite order, the results are very different. Because the wireframe shape has more holes in it, parts of the solid shape show through those holes. Figure 1-1 The painter’s model The Drawing Environment The drawing environment encompasses the digital canvas and graphics settings that determine the final look of your content. The canvas determines where your content is drawn, while the graphics settings control every aspect of drawing, including the size, color, quality, and orientation of your content. The Graphics Context You can think of a graphics context as a drawing destination. A graphics context encapsulates all of the information needed to draw to an underlying canvas, including the current drawing attributes and a device-specific representation of the digital paint on the canvas. In Cocoa, graphics contexts are represented by the NSGraphicsContext class and are used to represent the following drawing destinations: ● Windows (and their views) ● Images (including bitmaps of all kinds) Overview of Cocoa Drawing The Drawing Environment 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 14● Printers ● Files (PDF, EPS) ● OpenGL surfaces By far, the most common drawing destination is your application's windows, and by extension its views. Cocoa maintains graphics context objects on a per-window, per-thread basis for your application. This means that for a given window, there are as many graphics contextsfor that window asthere are threadsin your application. Although most drawing occurs on your application's main thread, the additional graphics context objects make it possible to draw from secondary threads as well. For most other drawing operations, Cocoa creates graphics contexts as needed and configures them before calling your drawing code. In some cases, actions you take may create a graphics context indirectly. For example, when creating a PDF file, you might simply request the PDF data for a certain portion of your view object. Behind the scenes, Cocoa actually creates a graphics context object and calls your view's drawing code to generate the PDF data. You can also create graphics contexts explicitly to handle drawing in special situations. For example, one way to create a bitmap image is to create the bitmap canvas and then create a graphics context that draws directly to that canvas. There are other waysto create graphics context objects explicitly, although most involve drawing to the screen or to an image. It is very rare that you would ever create a graphics context object for printing or generating PDF or EPS data. For information about graphics contexts, see “Graphics Contexts” (page 24). The Graphics State In addition to managing the drawing destination, an NSGraphicsContext object also manages the graphics state associated with the current drawing destination. The graphics state consists of attributes that affect the way content is drawn,such asthe line width,stroke color, and fill color. The current graphicsstate can be saved on a stack that is maintained by the current graphics context object. Any subsequent changes to the graphics state can then be undone quickly by simply restoring the previous graphics state. This ability to save and restore the graphics state provides a simple way for your drawing code to return to a known set of attributes. Cocoa manages some attributes of the graphics state in a slightly different way than Quartz does. For example, the currentstroke and fill color are set using the NSColor class, and most path-based parameters are set using the NSBezierPath class. This shift of responsibility reflects the more object-oriented nature of Cocoa. For more information about the attributes that comprise the current graphics state, and the objects that manage them, see “Graphics State Information” (page 27). Overview of Cocoa Drawing The Drawing Environment 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 15The Coordinate System The coordinate system supported by Cocoa is identical to the one used in Quartz-based applications. All coordinates are specified using floating-point valuesinstead of integers. Your code drawsin the user coordinate space. Your drawing commands are converted to the device coordinate space where they are then rendered to the target device. The user coordinate space uses a fixed scale for coordinate values. In this coordinate space, one unit is effectively equal to 1/72 of an inch. Although it seems like this might imply a 72 dots-per-inch (dpi) resolution for drawing, it is a mistake to assume that. In fact, the user coordinate space has no inherent notion of pixels or dpi. The use of floating-point values makes it possible for you to do precise layout in the user coordinate space and let Cocoa worry about converting your coordinates to the device space. As the name implies, the device coordinate space refers to the native coordinate space used by the target device, usually a monitor or printer. Unlike the user coordinate space, whose units are effectively fixed, the units of the device coordinate space are tied to the resolution of the target device, which can vary. Cocoa handles the conversion of coordinates from user space to the device space automatically during rendering, so you rarely need to work with device coordinates directly. For more information about coordinate systems in Cocoa, see “Coordinate Systems Basics” (page 41). Transforms A transform is a mathematical construct used to manipulate coordinatesin two-dimensionalspace. Transforms are used extensively in graphics-based computing to simplify the drawing process. Coordinate values are multiplied through the transform's mathematical matrix to obtain a modified coordinate that reflects the transform's properties. In Cocoa, the NSAffineTransform class implements the transform behavior. You use this class to apply the following effects to the current coordinate system: ● Translation ● Scaling ● Rotation You can combine the preceding effectsin different combinationsto achieve interesting results. During drawing, Cocoa applies the effects to the content you draw, imparting those characteristics on your shapes and images. Because all coordinates are multiplied through a transform at some point during rendering, the addition of these effects has little effect on performance. In fact, manipulating your shapes using transforms is often faster than manipulating your source data directly. Overview of Cocoa Drawing The Drawing Environment 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 16For more information about transforms, including how they affect your content and how you use them, see “Coordinate Systems and Transforms” (page 41). Color and Color Spaces Color is an important part of drawing. Before drawing any element, you must choose the colors to use when rendering that element. Cocoa provides complete support for specifying color information in any of several different color spaces. Support is also provided for creating colors found in International Color Consortium (ICC) and ColorSync profiles. Transparency is another factor that influencesthe appearance of colors. In OS X, transparency is used to render realistic-looking content and aesthetically appealing effects. Cocoa providesfullsupport for adding transparency to colors. In Cocoa, the NSColor and NSColorSpace classes provide the implementation for color objects and color space objects. For more information on how to work with colors in Cocoa, see “Color and Transparency” (page 65). Basic Drawing Elements The creation of complex graphics often has a simple beginning. In Cocoa, everything you draw is derived from a set of basic elementsthat you assemble in your drawing code. These elements are fundamental to all drawing operations and are described in the following sections. Geometry Support Cocoa provides its own data structures for manipulating basic geometric information such as points and rectangles. Cocoa defines the data types listed in Table 1-1. The member fields in each of these data structures are floating-point values. Table 1-1 Primitive data types Type Description A point data type consists of an x and y value. Pointsspecify the coordinatesfor a rendered element. For example, you use points to define lines, to specify the start of a rectangle, to specify the angle of an arc, and so on. NSPoint A size data type consists of a width and height field. Sizes are used to specify dimensions of a target. For example, a size data type specifies the width and height of a rectangle or ellipse. NSSize Overview of Cocoa Drawing Basic Drawing Elements 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 17Type Description A rectangle data type is a compound structure composed of an origin point and a size. The origin field specifiesthe location of the rectangle’s bottom-left corner in the current coordinate system. The size field specifies the rectangle’s height and width relative to the origin point and extending up and to the right. (Note, in flipped coordinate spaces, the origin point is in the upper-left corner and the rectangle’s height and width extend down and to the right.) NSRect For information on how to manipulate point, rectangle, and size data types, see “Manipulating Geometric Types” (page 142). Shape Primitives Cocoa provides support for drawing shape primitives with the NSBezierPath class. You can use this class to create the following basic shapes, some of which are shown in Figure 1-2. ● Lines ● Rectangles ● Ovals and circles ● Arcs ● Bezier cubic curves Figure 1-2 Examples of shape primitives Bezier path objects store vector-based path information, making them compact and resolution independent. You can create paths with any of the simple shapes or combine the basic shapes together to create more complex paths. To render those shapes, you set the drawing attributes for the path and then stroke or fill it to “paint” the path to your view. Overview of Cocoa Drawing Basic Drawing Elements 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 18Note: You can also add glyph outlinesto a Bezier path object using the methods of NSBezierPath. For most text handling, though, you should use the Cocoa text system, which is introduced in “Text” (page 127). For more information about drawing shapes, see “Paths” (page 130). Images Support for images is provided by the NSImage class and its associated image representation classes (NSImageRep and subclasses). The NSImage class contains the basic interface for creating and managing image-related data. The image representation classes provide the infrastructure used by NSImage to manipulate the underlying image data. Images can be loaded from existing files or created on the fly. Figure 1-3 shows some bitmap images loaded from files. Figure 1-3 Examples of bitmap images Cocoa supports many different image formats, either directly or indirectly. Some of the formats Cocoa supports directly include the following: ● Bitmap images, including the following image formats: ● BMP ● GIF ● JPEG ● JPEG 2000 Overview of Cocoa Drawing Basic Drawing Elements 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 19● PNG ● TIFF ● Images based on Encapsulated PostScript (EPS) data ● Images based on Portable Document Format (PDF) data ● Images based on PICT data ● Core Image images Because they support many types of data, you should not think of image objects strictly as bitmaps. Image objects can also store path-based drawing commands found in EPS, PDF, and PICT files. They can render data provided to them by Core Image. They can interpolate image data as needed and render the image at different resolutions as needed. For detailed information about Cocoa support for images and the ways to use images in your code, see “Images” (page 74). Gradients In OS X v10.5 and later, you can use the NSGradient class to create gradient fill patterns. Text Cocoa provides an advanced text system for drawing everything from simple strings to formatted text flows. Figure 1-4 shows some basic examples of stylized text that you can create. Figure 1-4 Examples of text Overview of Cocoa Drawing Basic Drawing Elements 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 20Because text layout and rendering using the Cocoa text system is a very complicated process, it is already well documented elsewhere and is not covered in great detail in this document. For basic information about drawing text and for links to more advanced text-related documents, see “Text” (page 127). Views and Drawing Nearly all drawing in Cocoa is done inside views. Views are objects that represent a visual portion of a window. Each view object is responsible for displaying some visual content and responding to user events in its visible area. A view may also be responsible for one or more subviews. The NSView classisthe base classfor all view-related objects. Cocoa definesseveral types of viewsfor displaying standard content, including text views, split views, tab views, ruler views, and so on. Cocoa controls are also based on the NSView class and implement interface elements such as buttons, scrollers, tables, and text fields. In addition to the standard views and controls, you can also create your own custom views. You create custom views in cases where the behavior you are looking for is not provided by any of the standard views. Cocoa notifies your view that it needsto draw itself by sending your view a drawRect: message. Your implementation of the drawRect: method is where all of your drawing code goes. Note: Although you can also subclassthe standard views and controlsto implement custom behavior, it isrecommended that you try to use a delegate object whenever possible instead. If you do subclass a standard control, avoid changing the appearance of that control. Doing so goes against the guidance in OS X Human Interface Guidelines. By default, window updates occur only in response to user actions. This means that your view’s drawRect: method is called only when something about your view has changed. For example, Cocoa calls the method when a scrolling action causes a previously hidden part of your view to be exposed. Cocoa also calls it in response to requests from your own code. If the information displayed by your custom view changes, you must tell Cocoa explicitly that you want the appropriate parts of your view updated. You do so by invalidating parts of your view’s visible area. Cocoa collects the invalidated regions together and generates appropriate drawRect: messages to redraw the content. Although there are numerous ways to draw, a basic drawRect: method has the following structure: - (void)drawRect:(NSRect)rect { // Draw your content } Overview of Cocoa Drawing Views and Drawing 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 21That's it! By the time your drawRect: method is called, Cocoa has already locked the drawing focus on your view, saved the graphics state, adjusted the current transform matrix to your view's origin, and adjusted the clipping rectangle to your view's frame. All you have to do is draw your content. In reality, your drawRect: method is often much more complicated. Your own method might use several other objects and methodsto handle the actual drawing. You also might need to save and restore the graphics state one or more times. Because this single method is used for all of your view's drawing, it also has to handle several different situations. For example, you might want to do more precise drawing during printing or use heavily optimized code during a live resizing operation. The options are numerous and covered in more detail in subsequent chapters. For additional information about views and live resizing, see View Programming Guide . For more information about printing in Cocoa, see “Customizing a View’s Drawing for Printing” in Printing Programming Guide for OS X . Common Drawing Tasks Table 1-2 lists some of the common tasks related to drawing the content of your view and offers advice on how to accomplish those tasks. Table 1-2 Common tasks and solutions Task How to accomplish Implement a drawRect: method in your custom view. Use your implementation of this method to draw content using paths, images, text, or any other tools available to you in Cocoa, Quartz, or OpenGL. Draw the content for a custom view. Send a setNeedsDisplayInRect: or setNeedsDisplay: message to the view. Sending either of these messages marks part or all of the view as invalid and in need of an update. Cocoa responds by sending a drawRect: message to your view during the next update cycle. Update a custom view to reflect changed content. Use Core Animation, set up a timer, or use the NSAnimation or NSViewAnimation classes, to generate notifications at a desired frame rate. Upon receiving the timer notification, invalidate part or all of your view to force an update. For information about Core Animation, see Core Animation Programming Guide . For more information about animating with timers, see “Using NSTimer for Animated Content” (page 124). For information about using NSAnimation objects, see “Using Cocoa Animation Objects” (page 125). Animate some content in a view. Overview of Cocoa Drawing Common Drawing Tasks 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 22Task How to accomplish Use the inLiveResize method of NSView to determine if a live resize is happening. If it is, draw as little as possible while ensuring your view has the look you want. For more information about live resizing optimizations, see Drawing Performance Guidelines. Draw during a live resize. Use the currentContextDrawingToScreen class method or isDrawingToScreen instancemethod of NSGraphicsContext to determine if a print operation is underway. Use the attributes method of NSGraphicsContext to retrieve (as needed) any additional information about the current print job. Draw images at the best possible resolution. Adjust your graphics in any other ways you think are appropriate to achieve the best possible appearance on the target device. For more information about printing, see Printing Programming Guide for OS X . Draw during a printing operation. Use the dataWithPDFInsideRect: or dataWithEPSInsideRect:method to obtain the data. In your drawRect: method use the currentContextDrawingToScreen class method or isDrawingToScreen instance method of NSGraphicsContext to determine if a print operation is underway. Create PDF or EPS data from a view. Overview of Cocoa Drawing Common Drawing Tasks 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 23Graphics contexts are a fundamental part of the drawing infrastructure in Cocoa applications. As the name suggests, a graphics context provides the context for subsequent drawing operations. It identifies the current drawing destination (screen, printer, file, and so on), the coordinate system and boundaries for the underlying canvas, and any graphics attributes associated with the destination. For most of the drawing you do in Cocoa, you never need to create a graphics context yourself. The normal drawing cycle in Cocoa automatically creates and configures a graphics context for you to use. For some advanced drawing, however, you may need to create your own graphics context prior to drawing. In a Cocoa application, graphics contexts for nearly all types of canvas are represented by the NSGraphicsContext class. You use graphics context objects to manipulate graphics attributes and to get information about the current drawing environment. Note: For OpenGL drawing, you use the NSOpenGLContext classinstead of NSGraphicsContext for the graphics context object. OpenGL drawing, and use of the NSOpenGLContext class, are covered in “Using OpenGL in Your Application” (page 165). This chapter provides an overview of Cocoa graphics contexts and how you use them in your application. It includes information on how to create custom graphics contexts and when it might be appropriate to do so. Graphics Context Basics The primary job of any graphics context object isto maintain information about the currentstate of the drawing environment. In Quartz, the graphics context object is associated with a window, bitmap, PDF file, or other output device and maintains information for that device. The same is true for a Cocoa graphics context, but because Cocoa drawing is view-based, some additional changes are made to the drawing environment before your view’s drawRect: method is called. By the time your view’s drawRect: method is called, Cocoa has made sure that any drawing calls you make stay within the confines of your view. It saves the graphics state to simplify the process of undoing its changes later. It adds an appropriate transform to the current transformation matrix to place the drawing origin at the 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 24 Graphics Contextsorigin of your view. It also sets the clipping region to your view's visible boundaries, preventing any rendered content from straying into other views. Your view is effectively the star of the show, at least until another view’s drawRect: method is called. While the current context is focused on your view, you can draw paths, images, text, or any other content you want. You can also change the attributes of the current drawing environment to achieve the appearance you want for your content. Eventually, the content you draw is sent to the Quartz Compositor, where it is combined with the content from other views in the window and flushed to the screen or output device. After your drawRect: method returns, Cocoa goesthrough the process of resetting the drawing environment for the next view. It reverts any changes you made to the drawing environment and sets up the coordinate transform and clipping region for the next view, giving it its own pristine environment in which to work. This process then repeats itself during each update cycle in your application. The Current Context Each thread in a Cocoa application has its own graphics context object for a given window. You can access this object from your code using the currentContext method of NSGraphicsContext, as shown in the following example: NSGraphicsContext* aContext = [NSGraphicsContext currentContext]; The currentContext method always returns the Cocoa graphics context object that is appropriate for the current drawing environment. This object keeps track of the current graphics state, lets you save and restore graphics state information, and lets you modify many graphics state attributes. The changes you make to the graphics state affect all subsequent drawing calls. If you change an attribute more than once, only the most recent setting is used. To save the current graphics state, you use the saveGraphicsState method of NSGraphicsContext. This method essentially pushes a copy of the current state onto a stack, leaving you free to make changes to the currentstate. When you want to revert back to the previousstate, you simply call the restoreGraphicsState method to pop the current graphics state (including all changes since the last save) off of the stack and restore the previous state. If you plan to change the current graphics state significantly, it is a good idea to save the current state before making your changes. Modifying one or two attributes usually may not merit saving the graphics state, since you can reset or change those individual attributes easily. However, if you are changing more than one or two attributes, it is usually easier to save and restore the entire graphicsstate. You can call the saveGraphicsState method as often as needed in your code to save snapshots of the current graphics state, but you must be sure to balance each call with a matching call to restoreGraphicsState. Graphics Contexts Graphics Context Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 25Note: The saveGraphicsState and restoreGraphicsState methods are available both as class methods and as instance methods. The class method versions simply save and restore the graphicsstate of the current context. The instance methodslet you save the state of a specific context object, although in most cases this should be the current context. The following example shows a simple drawRect: method that iterates over an array of developer-defined objects, each of which is drawn with a differentset of attributes. The graphicsstate issaved and restored during each loop iteration, ensuring that each object starts from the same graphics state. - (void)drawRect:(NSRect)rect { NSGraphicsContext* theContext = [NSGraphicsContext currentContext]; int i; int numObjects = [myObjectArray count]; // Iterate over an array of objects // Set the attributes for each before drawing for (i = 0; i < numObjects; i++) { [theContext saveGraphicsState]; // Set the drawing attributes // Draw the object [theContext restoreGraphicsState]; } } Warning: When saving and restoring the graphics state, you must balance all calls to saveGraphicsState with a corresponding call to restoreGraphicsState. Failure to do so can result in unexpected changes to the appearance of any windows that use that view. Graphics Contexts Graphics Context Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 26Graphics State Information Each Cocoa graphics context object maintainsinformation about the currentstate of the drawing environment. This information ranges from the global rendering settings to the attributes used to render the current path and is the same state information saved by Quartz. Whenever you save the current graphics state, you save a copy of the settings listed in Table 2-1. Table 2-1 Graphics state information Attribute Description Maps points in the view’s coordinate system to points in the destination device's coordinate system. Cocoa modifies the CTM before calling your view’s drawRect: method. You can use an NSAffineTransform object to modify the CTM further to change the drawing origin, scale the canvas, or rotate the coordinate system. For more information, see “Coordinate Systems and Transforms” (page 41). Current transformation matrix (CTM) Specifiesthe area of the canvasthat can be painted by drawing calls. Cocoa modifies the clipping region to the visible area of your view before calling its drawRect: method. You can use an NSBezierPath object to further clip the visible area. For more information, see “Setting the Clipping Region” (page 35). Clipping area Specifies the width of paths. The default line width is 1.0 but you can modify this value using an NSBezierPath object. For more information,see “Line Width” (page 134). Line width Specifies how two connected lines are joined together. The default join style is NSMiterLineJoinStyle but you can modify this value using an NSBezierPath object. For more information, see “Line Join Styles” (page 136). Line join style Specifies the appearance of an open end point on a path. The default line cap style is NSButtLineCapStyle but you can modify this value using an NSBezierPath object. For more information, see “Line Cap Styles” (page 135). Line cap style Defines a broken pattern for lines, including the initial phase for the style. There is no default dash style, resulting in solid lines. You modify dash styles for a path using an NSBezierPath object. For more information, see “Setting Path Attributes” (page 31). Line dash style Determines when lines should be joined with a bevel instead of a miter. Applies only when the line join style is set to NSMiterLineJoinStyle. The length of the miter is divided by the line width. If the resulting value is greater than the miter limit, a bevel is used. The default value is 10.0 but you can modify this value using an NSBezierPath object. For more information, see “Miter Limits” (page 139). Line miter limit Graphics Contexts Graphics Context Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 27Attribute Description Specifies the accuracy with which curves are rendered. (It is also the maximum error tolerance, measured in pixels.) Smaller numbers result in smoother curves at the expense of more calculations. The interpretation of this value may vary slightly on different rendering devices. The default value is 0.6 but you can modify this value using an NSBezierPath object. For more information, see “Line Flatness” (page 138). Flatness value Specifies the color used for rendering paths. This color applies only to the path line itself, not the area the path encompasses. You can specify colors using any of the system-supported color spaces. This value includes alpha information. Color information is managed by the NSColor class. For more information, see “Setting Colors and Patterns” (page 31). Stroke color Specifies the color used to fill the area enclosed by a path. You can specify colors using any of the system-supported color spaces. This value includes alpha information. Color information is managed by the NSColor class. For more information, see “Setting Colors and Patterns” (page 31). Fill color Specifies the shadow attributes to apply to rendered content. You set shadows using the NSShadow class. For more information, see “Adding Shadows to Drawn Paths” (page 111). Shadow Specifies the technique used to map in-gamut colors to the gamut of the current color space. Cocoa does not support setting this attribute directly. Instead, you must use Quartz. For more information, see “Mapping Physical Colors to a Color Space” (page 72). Rendering intent Specifies the font to use when drawing text. You modify font information using the NSFont class. For more information on drawing text,see “Text Attributes” (page 127). Font name Specifiesthe fontsize to use when drawing text. You modify font information using the NSFont class. For more information on drawing text,see “Text Attributes” (page 127). Font size Specifiesthe characterspacing to use when drawing text. (This attribute issupported only indirectly by Cocoa.) For more information on drawing text, see “Text Attributes” (page 127). Font character spacing Specifies how to render the text. (This attribute is supported only indirectly by Cocoa.) For more information on drawing text, see “Text Attributes” (page 127). Text drawing mode Specifies the process used to interpolate images during rendering. You use the NSGraphicsContext class to change this setting. For more information, see “Image Size and Resolution” (page 80) Image interpolation quality Graphics Contexts Graphics Context Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 28Attribute Description Specifies the process used to composite source and destination material together. (The compositing operations supported by Cocoa are related to the Quartz blend modes but differ in their usage and behavior.) You use the NSGraphicsContext classto set the default value for thissetting. Some rendering methods and functions may let you specify a different option. For more information, see “Setting Compositing Options” (page 32). Compositing operation Specifies a global alpha (transparency) value to apply in addition to the alpha value for a given color. Cocoa does not support this attribute directly. If you want to set it, you must use the CGContextSetAlpha function in Quartz. Global alpha Specifies whether paths use aliasing to smooth lines asthey cross pixel boundaries. You use the NSGraphicsContext class to change this setting. For more information, see “Setting the Anti-aliasing Options” (page 37). Anti-aliasing setting Note: The winding rule used to fill paths is not stored as part of the current graphics state. You can set a default winding rule for NSBezierPath objects but doing so affects content rendered using those objects. For more information, see “Winding Rules” (page 141). Screen Canvases and Print Canvases In a broad sense, Cocoa graphics context objects serve two types of canvases: screen-based canvases and print-based canvases. A screen-based graphics context renders content to a window, view, or image with the results usually appearing on a screen. A print-based graphics context is used to render content to a printer spool file, PDF file, PostScript file, EPS file, or other medium usually associated with the printing system. For nearly all screen-based and print-based drawing, Cocoa provides an appropriate graphics context object automatically. Cocoa provides a graphics context object during all view updates and in response to the user printing a document. There are situations, however, where you must create a graphics context object manually, including the following: ● Using OpenGL commands to render your view content ● Drawing to an offscreen bitmap ● Creating PDF or EPS data ● Initiating a print job programmatically Using the class methods of NSGraphicsContext, you can create graphics context objects for drawing to screen-based canvases. You cannot use these methods for print-based canvas, however. Cocoa routes all printing operations through the Cocoa printing system, which handles the task of setting up the graphics Graphics Contexts Graphics Context Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 29context object for you. This means that if you want to generate PDF data, EPS data, or print to a printer, you must use the methods of the NSPrintOperation class to create a print job for your target. It also means that your views should provide some minimal printing support if you want to produce well-formatted output for print-based canvases. Note: Although Cocoa does provide some support for creating OpenGL graphics contexts automatically, the default pixel format options are usually limited. In most cases, you will want to create a custom OpenGL graphics context with the pixel format options you need for drawing. For more information, see “Creating an OpenGL Graphics Context” (page 166). You can determine the type of canvas being managed by the current graphics context using the isDrawingToScreen instance method or currentContextDrawingToScreen class method of NSGraphicsContext. For print-based canvases, you can use the attributes method to get additional information about the canvas, such as whether it is being used to generate a PDF or EPS file. For more information about obtaining contexts for both screen-based and print-based canvases, see “Creating Graphics Contexts” (page 38). Graphics Contexts and Quartz The NSGraphicsContext class in Cocoa is a wrapper for a Quartz graphics context (CGContextRef data type). Both types manage the same basic information, and in fact, many methods of NSGraphicsContext simply call their Quartz equivalents. This relationship makes it easy to perform any Quartz-related drawing in your application. It also means that any time you have a Cocoa graphics context (an instance of the NSGraphicsContext class), you have a Quartz graphics context as well. For information on how to use Cocoa graphics contexts to call Quartz functions, see “Using Quartz in Your Application” (page 162). Modifying the Current Graphics State In your view’s drawRect: method, one of the first things you may want to do is modify the current drawing environment. For example, you might want to configure the current drawing colors, modifying the clipping region, transform the coordinate system, and so on. Many attributes can be set directly using the methods of NSGraphicsContext but some require the use of other objects. The following sections list the available drawing attributes and how you modify them. Graphics Contexts Modifying the Current Graphics State 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 30Important: Saving and restoring the current graphics state is a relatively expensive operation that should done as little as possible. In general, you should try to save and restore the graphics state only to undo several changes at once or when there is no alternative, such as to reset the clipping path. For individual changes, setting a new value directly is often more efficient than saving and restoring the entire graphics state. Setting Colors and Patterns Cocoa providessupport for colorsin a variety of different colorspaces. The NSColor classsupports RGB, CMYK, and grayscale color spaces by default but can also support custom color spaces defined by ICC and ColorSync profiles. The colors you specify include the color channels appropriate for the color space and an optional alpha component to define the transparency of the color. To set the currentstroke or fill attributes, create an NSColor object and send it a set, setStroke, or setFill message. The stroke and fill attributes define the color or pattern for paths and the areas they enclose. The currentstroke and fill colors affect all drawn content except text, which requiresthe application of text attributes; see “Applying Color to Text” (page 70). For more information about colors and how to create them, see “Color and Transparency” (page 65). Setting Path Attributes To modify the value of path attributes, you use the NSBezierPath class. Using the methods of this class, you can set the line width, line join style, line dash style, line cap style, miter limit, flatness, and winding rule attributes. All of these attributes affect the way paths are rendered by Cocoa. Path attributes come in two flavors: global and path-specific. When you use the class methodsin NSBezierPath to set the "default" value for an attribute, you are setting the global attribute. Global attributes are global to path objects (as opposed to the graphics state), so setting a global attribute affects all paths you render using the NSBezierPath class, but does not affect Quartz-based paths. To override a global attribute for an individual path object, you should set a path-specific value. For example, to set the global line width, you use the setDefaultLineWidth: class method of NSBezierPath. To set the line width for a specific NSBezierPath object, you use its setLineWidth: instance method. For information on how to set both default and path-specific attributes, and to see the resulting appearance of rendered content, see “Path Attributes” (page 133). Graphics Contexts Modifying the Current Graphics State 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 31Setting Text Attributes For most string-based drawing in Cocoa, you apply text attributes directly to the strings, rather than relying on the global font settings. The Cocoa string objects and the Cocoa text system both support the use of attributesfor modifying the appearance ofstring. For NSAttributedString objects, you apply the attributes directly to character ranges in the string. For regular NSString objects, you apply the attributes to the entire string when you draw it. If you want to set the global fontsettingsstored in the graphicsstate, perhapsfor drawing strings using Quartz, you can use the NSFont object to set the font family and size. After creating a font object, you use its set method to apply the font information to the current graphics state. For more information about drawing options for text, see “Text” (page 127). For more information about the Cocoa text system, see Cocoa Text Architecture Guide . Setting Compositing Options When you render each visual element, you need to decide how that element interacts with any surrounding content. You might want the element to be layered on top of or behind the current content or be merged with it in interesting ways. You specify this behavior using different compositing options. Compositing options specify how the colors in source content are blended with the existing content in the drawing destination. With fully opaque colors, most compositing optionssimply mask or overlay different parts of the source and destination content. With partially transparent colors, however, you can achieve interesting blending effects. The Cocoa compositing options differ from the blend modes used in Quartz, although the two perform basically the same task. The Cocoa options are inherited from the NextStep environment, whereas the Quartz blend modes are part of the newer PDF-based rendering model. Despite their historical legacy, the Cocoa options are still a very powerful way to composite content, and may even be a little easier to understand than their Quartz counterparts. Graphics Contexts Modifying the Current Graphics State 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 32Important: Despite their similarities, there is no direct mapping between the Cocoa compositing options and the Quartz blend modes. In addition, when drawing to a print-based canvas, you should use only the NSCompositeCopy or the NSCompositeSourceOver operators. (For PDF content, you should use only the NSCompositeSourceOver operator or the Quartz blend modes.) If you need to use any other compositing operators, you should render your content to an image and then draw the image to the printing context using one of the supported operators. If your application relies heavily on PDF blend modes, you may want to use Quartz for your drawing instead. Figure 2-1 shows the Cocoa compositing options and how they affect rendered content. At the top of the figure are the source and destination content being rendered. The veins of the leaf are completely transparent while the rest of the leaf is opaque. In the destination image, the color is rendered at partial opacity. Below that are the results for each of the supported compositing operations. Figure 2-1 Compositing operations in Cocoa Graphics Contexts Modifying the Current Graphics State 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 33Table 2-2 lists the mathematical equations used to compute pixel colors during compositing operations. In each equation, R is the resulting (premultiplied) color, S is the source color, D is the destination color, Sa is the alpha value of the source color, and Da is the alpha value of the destination color. All color component values and alpha values are in the range 0 to 1 for these computations. Table 2-2 Mathematical equations for compositing colors Para Para NSCompositeClear R = 0 NSCompositeCopy R = S NSCompositeSourceOver R = S + D*(1 - Sa) NSCompositeSourceIn R = S*Da NSCompositeSourceOut R = S*(1 - Da) NSCompositeSourceAtop R = S*Da + D*(1 - Sa) NSCompositeDestinationOver R = S*(1 - Da) + D NSCompositeDestinationIn R = D*Sa NSCompositeDestinationOut R = D*(1 - Sa) NSCompositeDestinationAtop R = S*(1 - Da) + D*Sa NSCompositeXOR R = S*(1 - Da) + D*(1 - Sa) NSCompositePlusDarker R = MAX(0, (1 - D) + (1 - S)) NSCompositePlusLighter R = MIN(1, S + D) To set the current compositing operation, you use the setCompositingOperation: method of NSGraphicsContext. This sets the global compositing option to use if no other operator is specified. The default compositing option is NSCompositeSourceOver. Graphics Contexts Modifying the Current Graphics State 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 34Setting the Clipping Region The clipping region is a useful way to limit drawing to a specific portion of your view. Instead of creating complex graphics offscreen and then compositing them precisely in your view, you can use a clipping region to mask out the portions of your view you do not want modified. For example, you might use a clipping region to prevent drawing commands from drawing over some already rendered content. Similarly, you might use a clipping region to cut out specific portions of an image you want to render. Before invoking your view’s drawRect: method, Cocoa configures the clipping region of the current graphics context to match the visible area of your view. This prevents your view's drawing code from rendering content outside of your view's boundaries, possibly on top of other views. You can restrict the drawable region of your view even further by adding shapesto the current clipping region. Whenever you add a new shape to the current clipping region, Cocoa determinesthe intersection of the shape with the current clipping region and uses the result as the new clipping region. This behavior means that you should generally add only one shape to the clip region before doing your drawing. The shape you add can be a single rectangle, multiple rectangles, or a combination of multiple complex subpathsin a single NSBezierPath object. For simple rectangular shapes, the easiest way to clip is using the NSRectClip function. To specify multiple rectangular regions, use the NSRectClipList function instead. To clip your view to a nonrectangular region, you must use an NSBezierPath object. The path you create can be arbitrarily complex and include multiple rectangular and nonrectangular regions. Once you have the path you want, use the object’s addClip method to add the resulting shape to the current clipping region. (For information on how to create paths,see “Drawing Fundamental Shapes” (page 144).) Graphics Contexts Modifying the Current Graphics State 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 35Figure 2-2 shows the effects of applying a clipping path to an image. The top images show the image to be clipped and the path to use for the clip shape, which in this case consists of two shapes inside a single NSBezierPath object. Although the clip shape is the same in both cases, the resulting clip region is different. This is because clipping takes into account the current winding rule when calculating the clipping region. Figure 2-2 Clipping paths and winding rules The following example shows you how to create the clip region shown in Figure 2-2. The clip region is composed of an overlapping square and circle, so you simply add a rectangle and oval with the appropriate sizes to a Bezier path object and call the addClip method. // If you plan to do more drawing later, it's a good idea // to save the graphics state before clipping. [NSGraphicsContext saveGraphicsState]; // Create the path and add the shapes NSBezierPath* clipPath = [NSBezierPath bezierPath]; [clipPath appendBezierPathWithRect:NSMakeRect(0.0, 0.0, 100.0, 100.0)]; Graphics Contexts Modifying the Current Graphics State 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 36[clipPath appendBezierPathWithOvalInRect:NSMakeRect(50.0, 50.0, 100.0, 100.0)]; // Add the path to the clip shape. [clipPath addClip]; // Draw the image. [NSGraphicsContext restoreGraphicsState]; Warning: Although you can also use the setClip method of NSBezierPath to modify the clipping region, doing so is not recommended. The setClip method replaces the entire clipping region with the area you specify. If the new clipping region extends beyond the bounds of your view, this could lead to portions of your content spilling over into neighboring views. Setting the Anti-aliasing Options Cocoa graphics contextssupport anti-aliasing in the same way that their Quartz counterparts do. Anti-aliasing is the process of artificially correcting the jagged (or aliased) edges surrounding text or shapes in bitmap images. These jagged edges occur primarily in lower-resolution bitmaps where it is easier to see individual pixels. To remove the jagged edges, Cocoa uses different colors for the pixels that surround a shape’s outline. Graphics Contexts Modifying the Current Graphics State 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 37The colors it uses are a blend of the original pixel color and the color of the shape’s outline. By blending colors in this way, the edges of the shape appear much smoother. Figure 2-3 shows the same image aliased and anti-aliased. Figure 2-3 A comparison of aliased and anti-aliased content To enable or disable anti-aliasing, use the setShouldAntialias: method of NSGraphicsContext. Even with anti-aliasing disabled, it may still appears as if Cocoa is drawing content using aliasing. When drawing content on non-pixel boundaries, Cocoa may opt to split the line over multiple pixels, which can give the impression of aliasing. For more information about how to avoid this situation, see “Doing Pixel-Exact Drawing” (page 61). Creating Graphics Contexts The type of drawing you do in your application will determine whether you need to create any graphics context objects explicitly orsimply use the one Cocoa provides you. If all you do is draw in your views, you can probably just use the Cocoa-provided context. This is true both for screen-based and print-based drawing. If your application performs any other type of drawing, however, you may need to create a graphics context yourself. The following sections provide information on how and when to create Cocoa graphics contexts for your content. Graphics Contexts Creating Graphics Contexts 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 38Creating a Screen-Based Context If you want to do any drawing outside of the normal update cycle of your view, you must create a graphics context object explicitly. You might use this technique to draw in an offscreen window or bitmap and then copy the resulting bits elsewhere. You could also use it to draw to a window from a secondary thread. The NSGraphicsContext classincludes methodsfor creating new graphics context objectsspecifically for windows and bitmap images. To draw to a window, you can use the graphicsContextWithWindow: method of NSGraphicsContext. The context you get back is initialized to the window itself, and not to a specific view. In fact, you may not want to use this technique if the window contains many subviews. In order to draw the views properly, you would need to walk the list of subviews manually and configure the drawing environment for each one, which is not recommended. Instead, you would use this technique for drawing to an offscreen buffer. Important: Because most OS X windows are already double-buffered, do not use offscreen windows or bitmaps simply to update the contents of a window. Doing so wastes memory (by adding a third buffer) and requires an extra copy operation to transfer the bits from the offscreen window to the window buffer. To draw to a bitmap, you have two options. If your code runs in OS X v10.4 and later, you can use the graphicsContextWithBitmapImageRep: method to create a context object focused on an NSBitmapImageRep object. The drawing you do is then rendered directly to the bitmap. If your code must run on earlier versions of OS X, you must either lock focus on a view or use an offscreen window and then capture the contents of the view or window. For information and examples on how to create bitmaps, see “Creating a Bitmap” (page 89) Creating a PDF or PostScript Context Unlike screen-based contexts, if you want to create a graphics context for a PDF, EPS, or print-based canvas, you do not do so directly. All print-based operations must go through the Cocoa printing system, which handles the work required for setting up the printed pages and running the print job. The simplest way to create a PDF or EPS file is to use the dataWithPDFInsideRect: and dataWithEPSInsideRect: methods of NSView. These methods configure a print job automatically and use your view's existing drawing code to generate the PDF or EPS data. For more information and an example of how to use these methods, see “Creating a PDF or EPS Image Representation” (page 93). To create a print job manually, you use the NSPrintOperation class. This class offers several class methods for creating print jobs for a particular view and outputting the job to a printer, PDF file, or EPS file. Once you have an instance of the NSPrintOperation class, you can set the print information and use the runOperation method to start the print job, at which point Cocoa takes over. Graphics Contexts Creating Graphics Contexts 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 39Important: You cannot create a viable graphics context for PDF or PostScript canvases using the graphicsContextWithAttributes: method. You must go through the Cocoa Printing system instead. During the execution of a print job, Cocoa calls several methods of your view to handle page layout and drawing. These methods are called for all printing paths, so implementing them for printing will also support PDF and EPS. For information on how to implement these methods, see Printing Programming Guide for OS X . Threading and Graphics Contexts The Application Kit maintains a unique graphics context for each window and thread combination. Because each thread has its own graphics context object for a given window, it is possible to use secondary threads to draw to that window. There are some caveats, however. During the normal update cycle for windows, all drawing requests are sent to your application’s main thread for processing. The normal update cycle happens when a user event triggers a change in your user interface. In this situation, you would call the setNeedsDisplay: or setNeedsDisplayInRect: method (or the display family of methods) from your application’s main thread to invalidate the portions of your view that require redrawing. You should not call these methods from any secondary threads. If you want to update a window or view from a secondary thread, you must manually lock focus on the window or view and initiate drawing yourself. Locking focus configures the drawing environment for that window's graphics context. Once locked, you can configure the drawing environment, issue your drawing commands as usual, and then flush the contents of the graphics context to the window buffer. In order to draw regularly on a secondary thread, you must notify the thread yourself. The simplest way to send regular notifications is using an NSTimer or NSAnimation object. For more information on how to animate content, see “Advanced Drawing Techniques” (page 111). Creating bitmaps on secondary threads is one way to thread your drawing code. Because bitmaps are self-contained entities, they can be created safely on secondary threads. From your thread, you would need to create the graphics context object explicitly (as described in “Creating a Screen-Based Context” (page 39)) and then issue drawing calls to draw into the bitmap buffer. For more information on how to create bitmaps, including sample code, see “Creating a Bitmap” (page 89). Important: Although drawing on secondary threads is allowed, you should always handle events and other user-requested actions from your application’s main thread only. Using multiple threads to handle events can lead to processing those events out of sequence, which can cause inconsistencies in your application’s behavior. Graphics Contexts Threading and Graphics Contexts 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 40Coordinate spaces simplify the drawing code required to create complex interfaces. In a standard Mac app, the window represents the base coordinate system for drawing, and all content must eventually be specified in that coordinate space when it is sent to the window server. For even simple interfaces, however, it is rarely convenient to specify coordinates relative to the window origin. Even the location of fixed items can change and require recalculation when the window resizes. This is where Cocoa makes things simple. Each Cocoa view you add to a window maintains its own local coordinate system for drawing. Rather than convert coordinate valuesto window coordinates, you simply draw using the local coordinate system, ignoring any changes to the position of the view. Before sending your drawing commands to the window server, Cocoa automatically corrects coordinate values and puts them in the base coordinate space. Even with the presence of local coordinate spaces, it is often necessary to change the coordinate space temporarily to affect certain behaviors. Changing the coordinate space is done using mathematical transformations (also known as transforms). Transforms convert coordinate values from one coordinate space to another. You can use transforms to alter the coordinate system of a view in a way that affects subsequent rendering calls, or you can use them to determine the location of points in the window or another view. The following sections provide information about how Cocoa manages the local coordinate systems of your views and how you can use transforms to affect your drawing environment. Coordinate Systems Basics Cocoa and Quartz use the same base coordinate system model. Before you can draw effectively, you need to understand this coordinate space and how it affects your drawing commands. It also helps to know the ways in which you can modify the coordinate space to simplify your drawing code. Local Coordinate Systems Cocoa uses a Cartesian coordinate system asits basic model forspecifying coordinates. The origin in thissystem is located in the lower-left corner of the current drawing space, with positive values extending along the axes up and to the right of the origin point. The root origin for the entire system is located in the lower-left corner of the screen containing the menu bar. 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 41 Coordinate Systems and TransformsIf you were forced to draw all your content in screen coordinates—the coordinate system whose origin is located at the lower-left corner of the computer’s primary screen—your code would be quite complex. To simplify things, Cocoa sets up a local coordinate system whose origin is equal to the origin of the window or view that is about to draw. Subsequent drawing calls inside the window or view take place relative to this local coordinate system. Once the code finishes drawing, Cocoa and the underlying graphics system convert coordinates in the local coordinates back to screen coordinates so that the content can be composited with content from other applications and sent to the graphics hardware. Note: If a computer has multiple monitors attached, those monitors can be set to mirror each other or to display one contiguous desktop. In mirroring mode, every screen has an origin of (0, 0). In contiguous mode, one screen has an origin of (0, 0) but other screens have origins that are offset from that of the first screen. Figure 3-1 shows the coordinate-system origin points of the screen, a window, and a view. In each case, the value to the bottom-left of each point is the coordinate measured in its parent coordinate system. (The screen does not have a parent coordinate system, so both coordinate values are 0). The window’s parent is the screen and the view’s parent is the window. Figure 3-1 Screen, window, and view coordinate systems on the screen Coordinate Systems and Transforms Coordinate Systems Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 42Mapping from screen coordinatesto local window or view coordinatestakes place in the current transformation matrix (CTM) of the Cocoa graphics context object. Cocoa applies the CTM automatically to any drawing calls you make,so you do not need to convert coordinate values yourself. You can modify the CTM though to change the position and orientation of the coordinate axesinside your view. (For more information,see “Transformation Operations” (page 46).) Points Versus Pixels The drawing system inOS X is based on a PDF drawing model, which is a vector-based drawing model. Compared to a raster-based drawing model, where drawing commands operate on individual pixels, drawing commands in OS X are specified using a fixed-scale drawing space, known as the user coordinate space. The system then maps the coordinates in this drawing space onto the actual pixels of the corresponding target device, such as a monitor or printer. The advantage of this model is that graphics drawn using vector commands scale nicely to any resolution device. As the device resolution increases, the system is able to use any extra pixels to create a crisper look to the graphics. In order to maintain the precision inherent with a vector-based drawing system, drawing coordinates are specified using floating-point values instead of integers. The use of floating-point values for OS X coordinates makes it possible for you to specify the location of your program's content very precisely. For the most part, you do not have to worry about how those values are eventually mapped to the screen or other output device. Instead, Cocoa takes care of this mapping for you. Even though the drawing model is based on PDF, there are still times when you need to render pixel-based content. Bitmap images are a common way to create user interfaces, and your drawing code may need to make special adjustmentsto ensure that any bitmap images are drawn correctly on different resolution devices. Similarly, you may want to ensure that even your vector-based graphics align properly along pixel boundaries so that they do not have an anti-aliased appearance. OS X provides numerous facilities to help you draw pixel-based content the way you want it. The following sections provide more detail about the coordinate spaces used for drawing and rendering content. There also follows some tips on how to deal with pixel-specific rendering in your drawing code. User Space The user coordinate space in Cocoa is the environment you use for all your drawing commands. It represents a fixed scale coordinate space, which means that the drawing commands you issue in this space result in graphics whose size is consistent regardless of the resolution of the underlying device. Units in the user space are based on the printer's point, which was used in the publishing industry to measure the size of content on the printed page. A single point is equivalent to 1/72 of an inch. Points were adopted by earlier versions of Mac OS as the standard resolution for content on the screen. OS X continues to use the same effective “resolution” for user-space drawing. Coordinate Systems and Transforms Coordinate Systems Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 43Although a single point often corresponded directly to a pixel in the past, in OS X, that may not be the case. Points are not tied to the resolution of any particular device. If you draw a rectangle whose width and height are exactly three points, that does not mean it will be rendered on the screen as a three-pixel by three-pixel rectangle. On a 144 dpi screen, the rectangle might be rendered using six pixels per side, and on a 600-dpi printer, the rectangle would require 25 pixels per side. The actual translation from points to pixels is device dependent and handled for you automatically by OS X. For all practical purposes, the user coordinate space is the only coordinate space you need to think about. There are some exceptions to this rule, however, and those are covered in “Doing Pixel-Exact Drawing” (page 61). Device Space The device coordinate space refers to the native coordinate space used by the target device, whether it be a screen, printer, file, or some other device. Units in the device coordinate space are specified using pixels and the resolution of this space is device dependent. For example, most monitors have resolutions in the 100 dpi range but printers may have resolutions exceeding 600 dpi. There are some devices that do not have a fixed resolution, however. For example, PDF and EPS files are resolution independent and can scale their content to any resolution. For Cocoa users, the device coordinate space is something you rarely have to worry about. Whenever you generate drawing commands, you always specify positions using user space coordinates. The only time that you might need to know about device space coordinates is when you are adjusting your drawn content to map more cleanly to a specific target device. For example, you might use device coordinates to align a path or image to specific pixel boundaries in order to prevent unwanted anti-aliasing. In such a situation, you can adjust your user space coordinates based on the resolution of the underlying device. For information on how to do this, see “Doing Pixel-Exact Drawing” (page 61) Resolution-Independent User Interface In OS X v10.4 and earlier, Quartz and Cocoa always treated screen devices as if their resolution were always 72 dpi, regardless of their actual resolution. This meant that for screen-based drawing, one point in user space was always equal to one pixel in device space. As screens advanced well past 100 dpi in resolution, the assumption that one point equaled one pixel began to cause problems. Most noticeably, everything became much smaller. In OS X v10.4, the first steps at decoupling the point-pixel relationship took place. In OS X v10.4, support was added for resolution independence in application user interfaces. The initial implementation of this feature provides a way for you to decouple your application’s user space from the underlying device space manually. You do this by choosing a scale factor for your user interface. The scale factor causes user space content to be scaled by the specified amount. Code that is implemented properly for resolution independence should look fine (albeit bigger). Code that is not implemented properly may see Coordinate Systems and Transforms Coordinate Systems Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 44alignment problems or pixel cracks along shape boundaries. To enable resolution independence in your application, launch Quartz Debug and choose Tools > Show User Interface Resolution, then set your scale factor. After changing the resolution, relaunch your application to see how it responds to the new resolution. For the most part, Cocoa applicationsshould not have to do anything special to handle resolution-independent UI. If you use the standard Cocoa views and drawing commands to draw your content, Cocoa automatically scales any content you draw using the current scale factor. For path-based content, your drawing code should require little or no changes. For images, though, you may need to take steps to make sure those images look good at higherscale factors. For example, you might need to create higher-resolution versionsto take advantage of the increased screen resolution. You might also need to adjust the position of images to avoid pixel cracks caused by images being drawn on non-integral pixel boundaries. For tips on how to make sure your content draws well at any resolution, see “Doing Pixel-Exact Drawing” (page 61). For more information about resolution independence and how it affects your code, see High Resolution Guidelines for OS X . Transform Basics Transforms are a tool for manipulating coordinates (and coordinate systems) quickly and easily in your code. Consider a rectangle whose origin is at (0, 0). If you wanted to change the origin of this rectangle to (10, 3), it would be fairly simple to modify the rectangle’s origin and draw it. Suppose, though, that you wanted to change the origin of a complex path that incorporated dozens of points and several Bezier curves with their associated control points. How easy would it be to recalculate the position of each point in that path? It would probably take a lot of time and require some pretty sophisticated calculations. Enter transforms. A transform is two-dimensional mathematical array used to map points from one coordinate space to another. Using transforms, you can scale, rotate, and translate content freely in two-dimensional space using only a few methods and undo your changes just as quickly. Support for transformsin Cocoa is provided by the NSAffineTransform class. The following sections provide background information about transforms and their effects. For additional information about how to use transforms in your code, see “Using Transforms in Your Code” (page 51). The Identity Transform The simplest type of transform is the identity transform. An identity transform maps any point to itself—that is, it does not transform the point at all. You always start with an identity transform and add transformations to it. Starting with the identity transform guarantees that you start from a known state. To create an identity transform, you would use the following code: Coordinate Systems and Transforms Transform Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 45NSAffineTransform* identityXform = [NSAffineTransform transform]; Transformation Operations For two-dimensional drawing, you can transform content in several different ways, including translating,scaling, and rotating. Transforms modify the coordinate system for the current drawing environment and affect all subsequent drawing operations. Before applying a transform, it is recommended that you save the current graphics state. The following sections describe each type of transformation and how it affects rendered content. Translation Translation involvesshifting the origin of the current coordinate system horizontally and vertically by a specific amount. Translation is probably used the most because it can be used to position graphic elements in the current view. For example, if you create a path whose starting point is always (0, 0), you could use a translation transform to move that path around your view, as shown in Figure 3-2. Figure 3-2 Translating content To translate content, use the translateXBy:yBy: method of NSAffineTransform. The following example changes the origin of the current context from (0, 0) to (50, 20) in the view's coordinate space: NSAffineTransform* xform = [NSAffineTransform transform]; [xform translateXBy:50.0 yBy:20.0]; [xform concat]; Coordinate Systems and Transforms Transform Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 46Scaling Scaling lets you stretch or shrink the units of the user space along the x and y axes independently. Normally, one unit in user space is equal to 1/72 of an inch. If you multiple the scale of either axis by 2, one unit on that axis becomes equal to 2/72 of an inch. This makes content drawn with scale factors greater than 1 appear magnified and content drawn with scale factors less than 1 appear shrunken. Figure 3-3 shows the effects of scaling on content. In the figure, a translation transform has already been applied so that the origin is located at (1, 1) in the original user space coordinate system. After applying the scaling transform, you can see the modified coordinate system and how it maps to the original coordinate system. Figure 3-3 Scaling content Although you might normally scale proportionally by applying the same scale factor to both the horizontal and vertical axes, you can assign different scale factors to each axis to create a stretched or distorted image. To scale content proportionally, use the scaleBy: method of NSAffineTransform. To scale content differently along the X and Y axes, use the scaleXBy:yBy: method. The following example demonstrates the scale factors shown in Figure 3-3: NSAffineTransform* xform = [NSAffineTransform transform]; [xform scaleXBy:2.0 yBy:1.5]; [xform concat]; Coordinate Systems and Transforms Transform Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 47Note: Scaling does not change the origin of the coordinate system. Rotation Rotation changes the orientation of the coordinate axes by rotating them around the current origin, as shown in Figure 3-4. You can change the orientation through a full circle of motion. Figure 3-4 Rotated content To rotate content, use the rotateByDegrees: or rotateByRadians: methods of NSAffineTransform. Positive rotation values proceed counterclockwise around the current origin. For example, to rotate the current coordinate system 45 degrees around the current origin point (as shown in Figure 3-4), you would use the following code: NSAffineTransform* xform = [NSAffineTransform transform]; [xform rotateByDegrees:45]; [xform concat]; Note: Combining a non-uniform scaling transform with a rotation transform can also give your content a skewed effect. Transformation Ordering The implementation of transforms uses matrix multiplication to map an incoming coordinate point to a modified coordinate space. Although the mathematics of matrices are covered in “Transform Mathematics” (page 50), an important factor to note is that matrix multiplication is not always a commutative operation—that is, a times b does not always equal b times a. Therefore, the order in which you apply transforms is often crucial to achieving the desired results. Coordinate Systems and Transforms Transform Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 48Figure 3-5 shows the two transformations applied to a path in two different ways. In the top part of the figure, the content is translated by 60 points along the X axis and then rotated 45 degrees. In the bottom part of the figure, the exact same transformations are reversed with the rotation preceding the translation. The end result is two different coordinate systems. Figure 3-5 Transform ordering The preceding figure demonstrates the key aspect of transformation ordering. Each successive transformation is applied to the coordinate system created by the previous transformations. When you translate and then rotate, the rotation begins around the origin of the translated coordinate system. Similarly, when you rotate and then translate, the translation occurs along the axes of the rotated coordinate system. For transformations of the same type, the order of the transformations does not matter. For example, three rotationsin a row creates a coordinate system whose final rotation is equal to the finalsum of the three rotation angles. There may be other cases (such as scaling by 1.0) where the order of the transforms does not matter, but you should generally assume that order is significant. Coordinate Systems and Transforms Transform Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 49Transform Mathematics All transform operations contribute to the building of a mathematical matrix that is then used by the graphics system to compute the screen location of individual points. The NSAffineTransform class uses a 3 x 3 matrix to store the transform values. Figure 3-6 showsthis matrix and identifiesthe key factors used to apply transforms. The m11 , m12 , m21 , and m22 values control both the scaling and rotation factors while t x and t y control translation. Figure 3-6 Basic transformation matrix Using linear algebra, it is possible to multiply a coordinate vector through the transform matrix to obtain a new coordinate vector whose position is equal to the original point in the new coordinate system. Figure 3-7 shows the matrix multiplication process and the resulting linear equations. Figure 3-7 Mathematical conversion of coordinates Coordinate Systems and Transforms Transform Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 50If you are already familiar with transform structures and the mathematics, you can set the values of a transform matrix directly using the setTransformStruct: method of NSAffineTransform. This method replaces the six key transform values with the new ones you specify. Replacing all of the values at once is much faster than applying individual transformations one at a time. It does require you to precompute the matrix values, however. Formore information aboutthemathematics behindmatrixmultiplications,seeQuartz 2DProgrammingGuide . Using Transforms in Your Code When it is time to draw, the code in your view’s drawRect: method must determine where to draw individual pieces of content. The position of some elements, such as images and rectangles, can be specified easily, but for complex elements like paths, transforms are an easy way to change the current drawing location. Creating and Applying a Transform To create a new transform object, call the transform class method of NSAffineTransform. The returned transform object is set to the identity transform automatically. After you have added all of the desired transformations to the transform object, you call the concat method to apply them to the current context. Calling concat adds your transformations to the CTM of the current graphics context. The modifications stay in effect until you explicitly undo them, as described in “Undoing a Transformation” (page 52), or a previous graphics state is restored. The following example creates a new transform object and adds several transformations to it. NSAffineTransform* xform = [NSAffineTransform transform]; // Add the transformations [xform translateXBy:50.0 yBy:20.0]; [xform rotateByDegrees:90.0]; // counterclockwise rotation [xform scaleXBy:1.0 yBy:2.0]; // Apply the changes [xform concat]; Coordinate Systems and Transforms Using Transforms in Your Code 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 51Undoing a Transformation Once applied, a transform affects all subsequent drawing calls in the current context. To undo a set of transformations, you can either restore a previous graphicsstate or apply an inverse transform. Both techniques have their advantages and disadvantages, so you should choose a technique based on your needs and the available information. Restoring a previous graphics state is the simplest way to undo a transformation but has other side effects. In addition to undoing the transform, restoring the graphicsstate reverts all other attributesin the current drawing environment back to their previous state. If you want to undo only the current transformation, you can add an inverse transform to the CTM. An inverse transform negates the effects of a given set of transformations using a complementary set of transformations. To create an inverse transform object, you use the invert method of the desired transform object. You then apply this modified transform object to the current context, as shown in the following example: NSAffineTransform* xform = [NSAffineTransform transform]; // Add the transformations [xform translateXBy:50.0 yBy:20.0]; [xform rotateByDegrees:90.0]; // counterclockwise rotation [xform concat]; // Draw content... // Remove the transformations by applying the inverse transform. [xform invert]; [xform concat]; You might use this latter technique to draw multiple items using the same drawing attributes but at different positions in your view. Depending on the type of transformations you use, you might also be able to do incremental transformations. For example, if you are calling translateXBy:yBy: only to reposition the origin, you could move the origin incrementally for each successive item. The following example, shows how you might position one item at (10, 10) and the next at (15, 10): [NSAffineTransform* xform = [NSAffineTransform transform]; // Draw item 1 [xform translateXBy:10.0 yBy:10.0]; Coordinate Systems and Transforms Using Transforms in Your Code 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 52[xform concat]; [item1 draw]; //Draw item 2 [xform translateXBy:5.0 yBy:0.0]; // Translate relative to the previous element. [xform concat]; [item2 draw]; Remember that the preceding techniques are used in cases where you do not want to modify your original items directly. Cocoa provides ways to modify geometric coordinates without modifying the current transformation matrix. For more information, see “Transforming Coordinates” (page 53). It is also worth noting that the effectiveness of an inverse transform is limited by mathematical precision. For rotation transforms, which involve taking sines and cosines of the desired rotation angle, an inverse transform may not be precise enough to undo the original rotation completely. In such a situation, you may want to simply save and restore the graphics state to undo the transform. Transforming Coordinates If you do not want to change the coordinate system of the current drawing environment, but do want to change the position or orientation of a single object, you have several options. The NSAffineTransform classincludesthe transformPoint: and transformSize: methodsfor changing coordinate values directly. Using these methods does not change the CTM of the current graphics context. If you want to alter the coordinates in a path, you can do so using the transformBezierPath: method of NSAffineTransform. This method returns a transformed copy of the specified Bezier path object. This method differs slightly from the transformUsingAffineTransform: method of NSBezierPath, which modifies the original object. Converting from Window to View Coordinates Events sent to your view by the operating system are sent using the coordinate system of the window. Before your view can use any coordinate values included with the event, it must convert those coordinates to its own local coordinate space. The NSView class provides several functions to facilitate the conversion of NSPoint, NSSize, and NSRect structures. Among these methods are convertPoint:fromView: and convertPoint:toView:, which convert pointsto and from the view’slocal coordinate system. For a complete list of conversion methods, see NSView Class Reference . Coordinate Systems and Transforms Using Transforms in Your Code 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 53Important: Cocoa event objects return y coordinate values that are 1-based (in window coordinates) instead of 0-based. Thus, a mouse click on the bottom left corner of a window or view would yield the point (0, 1) in Cocoa and not (0, 0). Only y-coordinates are 1-based. The following example converts the mouse location of a mouse event from window coordinates to the coordinates of the local view. To convert to the view’s local coordinate space, you use the convertPoint:fromView: method. The second parameter to this method specifies the view in whose coordinate system the point is currently specified. Specifying nil for the second parameter tells the current view to convert the point from the window’s coordinate system. NSPoint mouseLoc = [theView convertPoint:[theEvent locationInWindow] fromView:nil]; Coordinate Systems and Transforms Using Transforms in Your Code 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 54Flipped Coordinate Systems One topic that comes up frequently in Cocoa and Quartz is the use of flipped coordinate systems for drawing. By default, Cocoa uses a standard Cartesian coordinate system, where positive values extend up and to the right of the origin. It is possible, however, to “flip” the coordinate system, so that positive values extend down and to the right of the origin and the origin itself is positioned in the top-left corner of the current view or window, as shown in Figure 3-8. Figure 3-8 Normal and flipped coordinate axes Flipping the coordinate system can make drawing easier in some situations. Text systems in particular use flipped coordinates to simplify the placement of text lines, which flow from top to bottom in most writing systems. Although you are encouraged to use the standard Cartesian (unflipped) coordinate system whenever possible, you can use flipped coordinates if doing so is easier to support in your code. Configuring a view to use flipped coordinates affects only the content you draw directly in that view. Flipped coordinate systems are not inherited by child views. The content you draw in a view, however, must be oriented correctly based on the current orientation of the view. Failing to take into account the current view orientation may result in incorrectly positioned content or content that is upside down. Coordinate Systems and Transforms Flipped Coordinate Systems 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 55The following sections provide information about Cocoa support for flipped coordinates and some of the issues you may encounter when using flipped coordinate systems. Wherever possible, these sections also offer guidance on how to solve issues that arise due to flipped coordinate systems. Configuring Your View to Use Flipped Coordinates The first step you need to take to implement flipped coordinates is to decide the default orientation of your view. If you prefer to use flipped coordinates, there are two ways to configure your view’s coordinate system prior to drawing: ● Override your view’s isFlipped method and return YES. ● Apply a flip transform to your content immediately prior to rendering. If you plan to draw all of your view’s content using flipped coordinates, overriding the view’s isFlipped method is by far the preferred option. Overriding this method lets Cocoa know that your view wants to use flipped coordinates by default. When a view’s isFlipped method returns YES, Cocoa automatically makes several adjustments for you. The most noticeable change is that Cocoa adds the appropriate conversion transform to the CTM before calling your view’s drawRect: method. This behavior eliminates the need for your drawing code to apply a flip transform manually. In addition, many Cocoa objects automatically adjust their drawing code to account for the coordinate system of the current view. For example, the NSFont object automatically takes the orientation of the coordinate system into account when setting the current font. This prevents text from appearing upside down when drawn in your view. If you draw only a subset of your view’s content using flipped coordinates, you can use a flip transform (instead of overriding isFlipped) to modify the coordinate system manually. A flip transform lets you adjust the current coordinate system temporarily and then undo that adjustment when it is no longer needed. You would apply thistransform to your view’s coordinate system immediately prior to drawing the relevant flipped content. For information on how to create a flip transform, see “Creating a Flip Transform” (page 59). Drawing Content in a Flipped Coordinate System Most of the work you do to support flipped coordinates occurs within your application’s drawing code. If you chose to use flipped coordinates in a particular view, chances are it was because it made your drawing code easier to implement. Drawing in a flipped coordinate system requires you to position elements differently relative to the screen but is otherwise fairly straightforward. The following sections provide some tips to help you ensure any rendered content appears the way you want it. Coordinate Systems and Transforms Flipped Coordinate Systems 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 56Drawing Shape Primitives There are no real issues with drawing shape primitives in flipped coordinate systems. Shape primitives, such as rectangles, ovals, arcs, and Bezier curves can be drawn just as easily in flipped or unflipped coordinate systems. The only differences between the two coordinate systems is where the shapes are positioned and their vertical orientation. Laying out your shapes in advance to determine their coordinate points should solve any orientation issues you encounter. Drawing With Application Kit Functions The Application Kit framework contains numerousfunctionsfor quickly drawing specific content. Among these functions are NSRectFill, NSFrameRect, NSDrawGroove, NSDrawLightBezel, and so on. When drawing with these functions, Cocoa takesinto account the orientation of the target view. Thus, if your view usesflipped coordinates, these functions continue to render correctly in that flipped coordinate space. Drawing Images When rendering images in your custom views, you must pay attention to the relative orientation of your view and any images you draw in that view. If you draw an image in a flipped view using the drawInRect:fromRect:operation:fraction: method, your image would appear upside down in your view. You could fix this problem using one of several techniques: ● You could apply a flip transform immediately prior to drawing the image; see “Creating a Flip Transform” (page 59). ● You could use one of the compositeToPoint methods of NSImage to do the drawing. ● You could invert the image data itself. (Although a suitable fix, this is usually not very practical.) Using a flip transform to negate the effects of a flipped view ensures that your image contents are rendered correctly in all cases. This technique retains any previous transformations to the coordinate system, including scales and rotations, but removes the inversion caused by the view being flipped. You should especially use thistechnique if you needed to draw your image using the drawInRect:fromRect:operation:fraction: method of NSImage. This method lets you scale your image to fit the destination rectangle and is one of the more commonly used drawing methods for images. Although the compositeToPoint methods of NSImage provide you with a way to orient images properly without a flip transform, their use is not recommended. There are some side effects that make drawing with these methods more complicated. The compositeToPoint methods work by removing any custom scaling or rotation factors that you applied to the CTM. These methods also remove any scaling (but not translations) applied by any flip transforms, whether the transform was supplied by you or by Cocoa. (The methods also do not remove the scale factor in effect from resolution independence.) Any custom translation factors you applied Coordinate Systems and Transforms Flipped Coordinate Systems 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 57to the CTM are retained, however. Although this behavior is designed to ensure that images are not clipped by your view’s bounding rectangle, if you do not compensate for the flip transform’stranslation factor, clipping may still occur. Figure 3-9 shows what happens when you render an image in an unflipped view, and then in a flipped view, using the compositeToPoint:fromRect:operation: method. In the unflipped view, the image renders as expected at the specified point in the view. In the flipped view, the scale factor for the y-axis is removed but the translation factor is not, which results in the image being clipped because it appears partially outside the view’s visible bounds. To compensate, you would need to adjust the y-origin of the image by subtracting the original value from the view height to get the adjusted position. Figure 3-9 Compositing an image to a flipped view The issues related to the drawing of images in a flipped coordinate system are essentially independent of how you create those images in the first place. Images use a separate coordinate system internally to orient the image data. Whether you load the image data from an existing file or create the image by locking focus on it, Coordinate Systems and Transforms Flipped Coordinate Systems 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 58once the image data is loaded or you unlock focus, the image data is set. At that point, you must choose the appropriate drawing method or adjust the coordinate system yourself prior to drawing to correct for flipped orientation issues. Important: Although the setFlipped: method of NSImage might seem like a good way to change the orientation of an image after the fact, that is not actually the case. The setFlipped: method is there to let you specify the orientation of the image data before you issue a lockFocus call and draw into the image. Using that method to correct for flipped coordinate systems during drawing might seem to work at times, but it is not a reliable way to flip images and its use in that capacity is highly discouraged. For more information about images and their internal coordinate systems,see “Image Coordinate Systems” (page 81). Important: Regardless of whether the contents of the image are flipped or unflipped, you always specify the location and size of the image using the coordinate system of the current context. Drawing Text The text rendering facilities in Cocoa take their cues for text orientation from the current view. If your view’s isFlipped method returns YES, Cocoa automatically inverts the text drawn in that view to compensate for its flipped coordinate system. If you apply a flip transform manually from your drawing code, however, Cocoa does not know to compensate when drawing text. Any text you render after applying a flip transform manually therefore appears upside down in your view. These rules apply whether you are using the Cocoa text system or the drawing facilities of NSString to draw your text. If you lock focus on an image and draw some text into it, Cocoa uses the internal coordinate system of the NSImage object to determine the correct orientation for the text. As with other image content, if you subsequently render the image in a flipped view, the text you drew is flipped along with the rest of the image data. For more information about working with text, see “Text” (page 127). Creating a Flip Transform If you want to flip the coordinate system of your view temporarily, you can create a flip transform and apply it to the current graphics context. A flip transform is an NSAffineTransform object configured with two transformations: a scale transformation and a translate transformation. The flip transform works by flipping the direction of the y axis (using the scale transformation) and then translating the origin to the top of the view. Coordinate Systems and Transforms Flipped Coordinate Systems 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 59Listing 3-1 shows a drawRect: method that creates a flip transform and applies it to the current context. The flip transform shown here translatesthe origin first before reversing the direction of the vertical axis. You could also implement this transform by reversing the vertical axis first and then translating the origin in the negative direction—that is, using the negated value of the frame height. Listing 3-1 Flipping the coordinate system manually - (void)drawRect:(NSRect)rect { NSRect frameRect = [self bounds]; NSAffineTransform* xform = [NSAffineTransform transform]; [xform translateXBy:0.0 yBy:frameRect.size.height]; [xform scaleXBy:1.0 yBy:-1.0]; [xform concat]; // Draw flipped content. } The flip transform merely toggles the orientation of the current coordinate system. If your view already draws using flipped coordinates, because its isFlipped method returns YES, applying a flip transform reverts the coordinate system back to the standard orientation. Cocoa Use of Flipped Coordinates Some Cocoa classes inherently support flipped coordinates and some do not. If you are using unmodified Cocoa views and controls in your user interface, it should not matter to your code whether those views and controls use flipped coordinates. If you are subclassing, however, it isimportant to know the coordinate system orientation. The following controls and views currently use flipped coordinates by default: ● NSButton ● NSMatrix ● NSProgressIndicator ● NSScrollView ● NSSlider ● NSSplitView ● NSTabView ● NSTableHeaderView Coordinate Systems and Transforms Flipped Coordinate Systems 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 60● NSTableView ● NSTextField ● NSTextView Some Cocoa classes support flipped coordinates but do not use them all the time. The following list includes the known cases where flipped-coordinate support depends on other mitigating factors. ● Images do not use flipped coordinates by default; however, you can flip the image’s internal coordinate system manually using the setFlipped: method of NSImage. All representations of an NSImage object use the same orientation. For more information about images and flipped coordinates, see “Image Coordinate Systems” (page 81). ● The Cocoa text system takes cues from the current context to determine whether text should be flipped. If the text is to be displayed in an NSTextView object, text system objects (such as NSFont) also uses flipped coordinates to ensure that text is rendered right-side up. If you are drawing text in a custom view that uses standard coordinate, the text system objects do not use flipped coordinates. ● An NSClipView object determines whether to use flipped coordinates by looking at the coordinate system of its document view. If the document view uses flipped coordinates, so does the clip view. Using the same coordinate system ensures that the scroll origin matches the bounds origin of the document view. ● Graphics convenience functions,such asthose declared in NSGraphics.h, take flipped coordinate systems into account when drawing. For information about the available graphics convenience functions, see Application Kit Functions Reference . As new controls and views are introduced in Cocoa, those objects may also support flipped coordinates. Check the class reference documentation for any subclassing notes on whether a class supports flipped coordinates. You can also invoke the view’s isFlipped method at runtime to determine if it uses flipped coordinates. Doing Pixel-Exact Drawing Although it is possible to create applications using only the views, controls, and images provided by Cocoa, it is common for applications to use one or more custom views or images. And although Cocoa provides default behavior for laying out custom content, there are many times when you may want to adjust the position of individual views or imagesto avoid visual artifacts. Thisis especially true when tiling or drawing bitmap images on high-resolution devices(such as printers) or devices where resolution independentscale factors are in effect. The following sections provide guidelines and practical advice for how to prevent visual artifactsthat can occur during high-resolution drawing. For additional information on resolution independence and how to adapt your code to support different scale factors, see High Resolution Guidelines for OS X . Coordinate Systems and Transforms Doing Pixel-Exact Drawing 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 61Tips for Resolution Independent Drawing in Cocoa Cocoa applications provide a tremendous amount ofsupport for rendering to high-resolution devices. Although much of this support is automatic, you still need to do some work to ensure your content looks good. The following list includes some approaches to take when designing your interface: ● Use high-resolution images. ● During layout, make sure views and images are positioned on integral pixel boundaries. ● When creating tiled background images for custom controls, use the NSDrawThreePartImage and NSDrawNinePartImage methods to draw your background rather than trying to draw it yourself. ● Use antialiased text rendering modes for non-integral scale factors and be sure to lay out your text views on pixel boundaries. ● Test your applications with non-integral scale factors such as 1.25 and 1.5. These factors tend to generate odd numbers of pixels, which can reveal potential pixel cracks. If you are using OpenGL for drawing, you should also be aware that in OS X v10.5, the bounding rectangle of a view drawn into an NSOpenGLContext is measured in pixels and not in points (as it is in non OpenGL situations). This support may change in the future, however, so OpenGL developers should be sure to convert coordinates directly using the coordinate conversion methods of NSView. For example, the following conversion code for a view object is guaranteed to return the correct values needed by OpenGL. NSSize boundsInPixelUnits = [self convertRect:[self bounds] toView:nil]; glViewport(0, 0, boundsInPixelUnits.size.width, boundsInPixelUnits.size.height); For more information about resolution independence and how it affectsrendered content,see High Resolution Guidelines for OS X . Accessing the Current Scale Factor Knowing the current scale factor can help you make decisions about how best to render your content. The NSWindow and NSScreen classes both include a userSpaceScaleFactor method that you can call to obtain the current scale factor, if any, for your application. In OS X v10.5 and earlier, this method usually returns 1.0, indicating that the user space and device space have the same resolution (where one point equals one pixel). At some point though, this method may return a value that is greater than 1.0. For example, a value of 1.25 would indicate a screen resolution of approximately 90 dpi, while a value of 2.0 would indicate a screen resolution of 144 dpi. Coordinate Systems and Transforms Doing Pixel-Exact Drawing 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 62If you want to know the actual resolution of a particularscreen, the NSScreen classincludesinformation about the display resolution in its device description dictionary (accessed using the deviceDescription method). You can use this information (instead of multiplying scale factors) to determine the appropriate resolution to use for your images. Adjusting the Layout of Your Content Because screens are relatively low-resolution devices, drawing glitches are often more noticeable on a screen than they are on higher-resolution devices such as printers. Drawing glitches can occur when you render content in a way that requirestweaking to match the underlying pixelssent to the screen. For example, images and shapes drawn on non-pixel boundaries might require aliasing and therefore might appear less crisp than those drawn exactly on pixel boundaries. In addition, scaling an image to fit into a different-sized area requires interpolation, which can introduce artifacts and graininess. Although pixel-alignment issues can occur on any version of OS X, they are more likely to occur asthe operating system changes to support resolution independence. Under resolution independence, units in the user coordinate space and device coordinate space are no longer required to maintain a one-to-one relationship. For high-resolution screens, this means that a single unit in user space may be backed by multiple pixels in device space. So even if your user-space coordinatesfall on integral unit boundaries, they may still be misaligned in device space. The presence of extra pixels can also lead to pixel cracks, which occur when misaligned shapes leave small gaps because they do not fill the intended drawing area entirely. If your images or shapes are not drawing the way you expect, or if your graphics content displays evidence of pixel cracks, you can remove many of these issues by adjusting the coordinate values you use to draw your content. The following steps are not required if the current scale factor is 1.0 but would be required for other scale factors. 1. Convert the user-space point, size, or rectangle value to device space coordinates. 2. Normalize the value in device space so that it is aligned to the appropriate pixel boundary. 3. Convert the normalized value back to user space. 4. Draw your content using the adjusted value. The best way to get the correct device-space rectangle is to use the centerScanRect: method of NSView. This method takes a rectangle in userspace coordinates, performsthe needed calculationsto adjust the position of rectangles based on the current scale factor and device, and returns the resulting user space rectangle. For layout, you can also use the methods described in “Converting Coordinate Values” (page 64). If you want more control over the precise layout of items in device space, you can also adjust coordinates yourself. OS X provides several functions for normalizing coordinate values once they are in device space, including the NSIntegralRect and CGRectIntegral functions. You can also use the ceil and floor functions in math.h to round device space coordinates up or down as needed. Coordinate Systems and Transforms Doing Pixel-Exact Drawing 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 63Converting Coordinate Values In OS X v10.5, several methods were added to NSView to simplify the conversion between user space and device space coordinates: ● convertPointToBase: ● convertSizeToBase: ● convertRectToBase: ● convertPointFromBase: ● convertSizeFromBase: ● convertRectFromBase: These convenience methods make it possible to convert values to and from the base (device) coordinate system. They take into account the current backing store configuration for the view, including whether it is backed by a layer. To change the coordinate values of an NSPoint structure, the beginning of your view’s drawRect: method might have code similar to the following: - (void)drawRect:(NSRect)rect { NSPoint myPoint = NSMakePoint(1.0, 2.0); CGFloat scaleFactor = [[self window] userSpaceScaleFactor]; if (scaleFactor != 1.0) { NSPoint tempPoint = [self convertPointToBase:myPoint]; tempPoint.x = floor(tempPoint.x); tempPoint.y = floor(tempPoint.y); myPoint = [self convertPointFromBase:tempPoint]; } // Draw the content at myPoint } It is up to you to determine which normalization function is best suited for your drawing code. The preceding example uses the floor function to normalize the origin of the given shape but you might use a combination of floor and ceil depending on the position of other content in your view. Coordinate Systems and Transforms Doing Pixel-Exact Drawing 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 64One of the keys to creating interesting graphics is the effective use of color and transparency. In OS X, both are used to convey information and provide an inherent appeal to your creations. Good color usage usually results in an interface that is pleasing to the user and helps call out information when it is needed. About Color and Transparency Support for color in Cocoa is built on top of Quartz. The NSColor class provides the interface for creating and manipulating colors in a variety of color spaces. Other classes provide color and color space management. Cocoa also provides classes that present a user interface for selecting colors. For a more thorough explanation of color, color theory, and color management in OS X,see Color Management Overview and Color Programming Topics. Color Models and Color Spaces The human eye perceives photons in a fairly narrow band of the electromagnetic spectrum. Each photon vibrates at a frequency that defines the color of the light represented by that photon. The biology of the eye makes it particularly receptive to red, blue, and green light and these primary colors are often mixed together to create a broad range of perceptible colors. A color model is a geometric or mathematical framework that attempts to describe the colors seen by the eye. Each model contains one or more dimensions, which together represent the visible spectrum of color. Numerical values are pinned to each dimension making it possible to describe colors in the color model numerically. Having a numerical representation makes it possible to describe, classify, compare, and order those colors. A color space is a practical adaptation of a color model. It specifies the gamut (or range) of colors that can be produced using a particular color model. While the color model determines the relationship between values in each dimension, the color space defines the absolute meaning of those values as colors. Cocoa supports the same color spaces as Quartz 2D, although accessor methods of NSColor focus on the following color spaces: ● RGB ● CMYK ● Gray 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 65 Color and TransparencyIn Cocoa, the NSColorSpace class handles the information associated with a particular color space. You can create instances of this class to represent individual color spaces. Cocoa provides methods for retrieving color space objects representing the standard color spaces. You can also create custom color space objects using a ColorSync profile reference or International Color Consortium (ICC) profile data. For detailed information about color spaces and color models in OS X, see Color Management Overview. Color Objects The NSColor class in Cocoa provides the interface you need to create and manage individual colors. The NSColor classisitself a factory classfor creating the actual color objects. The class methods of NSColor create color objects that are actually based on specific subclasses of NSColor, where each subclass implements the behavior for a specific color space. Because a color object must represent a single color space, you cannot use all of the methods of NSColor from the same object. For a given color object, you can use only the methods that are relevant to colors in that object’s color space. For example, if you create an CMYK-based color object, you cannot use the getRed:green:blue:alpha: method to retrieve RGB values. Methods that are unsupported in the current color space raise an exception. For more information on how to create and use colors, see “Creating Colors” (page 68). Color Component Values In Cocoa, color space values, called components, are specified as floating-point values in the range 0.0 to 1.0. When working with other color values from other systems, you must convert any values that do not fall into the supported range. For example, if you use a color system whose components have values in the range 0 to 255, you must divide each component value by 255 to get the appropriate value for Cocoa. You can retrieve the component values of a color object using any of several methods in NSColor. Several methods exist for retrieving the color values of known color spaces, such as RGB, CMYK, HSV (also known as HSB), and gray. If you do not know the number of components in the color’s color space, you can use the numberOfComponents method to find out. You can then use the getComponents: method to retrieve the component values. Transparency In addition to the component values used to identify a particular color in a colorspace, OS X colors also support an alpha component for identifying the transparency of that color. Color and Transparency About Color and Transparency 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 66Transparency is a powerful effect used to give the illusion of light passing through a particular area instead of reflecting off of it. When you render an object using a partially transparent color, the object picks up some color from the object directly underneath it. The amount of color it picks up depends on the value of the color’s alpha component and the compositing mode. Like color components, the alpha component is specified as a floating-point value in the range 0.0 to 1.0. You can think of the alpha component as specifying the amount of light being reflected back from the object’s surface. An alpha value of 1.0 represents a 100% reflection of all light and is equivalent to the object being opaque. An alpha value of 0.0 represents 0% reflection of light and all color coming from the content underneath. An alpha value of 0.5 represents 50% reflection, with half the color being reflected off the object and half coming from the content underneath. You specify transparency when you create a color object. If you create a color using component values, you can specify an alpha value directly. If you have an existing color object, you can use the colorWithAlphaComponent: method to create a new color object with the same color components as the original but with the alpha value you specify. Pattern Colors In addition to creating monochromatic colors, you can also create pattern colors using images. Pattern colors are most applicable asfill colors but can be used asstroke colors as well. When rendered, the image you specify is drawn on the path or its fill area instead of a solid color. If an image is too small to fill the given area, it is tiled vertically and horizontally, as shown in Figure 4-1. Figure 4-1 Drawing with a pattern For information on how to create pattern colors, see “Creating Colors” (page 68). Color and Transparency About Color and Transparency 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 67Color Lists A color list is a dictionary-like object (implemented by the NSColorList class) that contains an ordered list of NSColor objects, identified by keys. You can retrieve colors from the color list by key. You can also organize the colors by placing them at specific indexes in the list. Color lists are available as a tool to help you manage any document-specific colors. They are also used to customize the list of colors displayed in a color panel. You can use the attachColorList: method of NSColorPanel to add any colors your application uses to the panel. For more information about using color lists and color panels, see Color Programming Topics. Color Matching Cocoa provides automatic color matching whenever possible using ColorSync. Color matching ensures that the colors you use to draw your content look the same on different devices. Cocoa provides full support for creating and getting color profile information using the NSColorSpace class. Cocoa supports both ColorSync profile references and ICC profiles as well as calibrated and device-specific profiles for the RGB, CMYK, and gray color spaces. Because color matching is automatic, there is nothing to do in your code except use the colors you want. For information about ColorSync, see ColorSync Manager Reference . For information on ICC profiles, see the International Color Consortium website: http://www.color.org/. Creating Colors The NSColor class supports the creation of several different types of color objects: ● Commonly used colors, such as red, green, black, or white ● System colors,such asthe current control color or highlight color, whose values are set by user preferences ● Calibrated colors belonging to a designated color space ● Device colors belonging to the designated device color space ● Pattern colors To create most color objects, simply use the appropriate class method of NSColor. The class defines methods for creating preset colors or for creating colors with the values you specify. To create a pattern color, load or create the desired image and pass it to the colorWithPatternImage: method of NSColor. For more information, see the NSColor class reference. For information on how to load and create images, see “Images” (page 74). Color and Transparency Creating Colors 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 68Important: Never allocate and initialize an NSColor object directly. Because it is a base class, the implementation of NSColor is minimal and simply throws an exception in situations where actual color information is required. In OS X v10.5 and later, Cocoa provides support for gradient fill patterns through the NSGradient class. Prior to version 10.5, if you want to use a gradient to fill or stroke a path, you must use Quartz instead. For examples of how to create and use gradients, see “Creating Gradient Fills” (page 113). Working with Colors Once you have an NSColor object, you can apply it to the stroke or fill color of the current context. Once set, any shapes you draw in the current context take on that color. You can also use the color component information in any calculations you might need for your program. Applying Colors to Drawn Content Stroke and fill colors modify the appearance of path-based shapes,such asthose drawn with the NSBezierPath class or functions such as NSRectFill. The stroke color applies to the path itself, and the fill color applies to the area bounded by that path. To set the current stroke or fill attributes, you use one of the NSColor methods listed in Table 4-1. Table 4-1 Methods for changing color attributes NSColor method Description set Sets both the stroke and fill color to the same value. setFill Sets the fill color. setStroke Sets the stroke color. For example, the following code sets the stroke color to black and the fill color to the background color for controls. [[NSColor blackColor] setStroke]; [[NSColor controlBackgroundColor] setFill]; Color and Transparency Working with Colors 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 69All subsequent drawing operations in the current context would use the specified colors. If you do not want any color to be drawn for the stroke or fill, you can set the current stroke or fill to a completely transparent color, which you can get by calling the clearColor method of NSColor. You can also create a transparent color by setting the alpha of any other color to 0. Note: Stroke and fill colors do not affect the appearance of text. To apply color to text, you must change the attributes associated with the text. Applying Color to Text Unlike many graphics operations, text is not drawn using the current stroke and fill colors. Instead, to apply color to text, you must apply color attributes to the characters of the corresponding string object. To apply color to a range of characters in an NSAttributedString object, you apply the NSForegroundColorAttributeName attribute to the characters. This attribute takes a corresponding NSColor object as its value. To apply color to the characters of an NSString object, you apply the NSForegroundColorAttributeName attribute just as you would for an NSAttributedString object. The difference in application isthat attributes applied to an NSString object affect the entire string and not a specified range of characters. The set of available attributesfor both string typesislisted in NSAttributedString Application Kit Additions Reference in the Application Kit Framework Reference . For an example of how to change the attributes of an attributed string, see “Changing an Attributed String” in Attributed String Programming Guide . For more information about drawing text, see “Text” (page 127). Getting the Components of a Color If your program manipulates colors in any way, you may want to know the component values for the colors you use. NSColor provides the following accessor methods for retrieving component values of a color: ● numberOfComponents ● getComponents: ● getRed:green:blue:alpha: ● getCyan:magenta:yellow:black:alpha: ● getHue:saturation:brightness:alpha: ● getWhite:alpha: Color and Transparency Working with Colors 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 70The NSColor class also provides methods for accessing individual component values, rather than all of the components together. For more information, see the NSColor class reference. Important: It is a programming error to ask an NSColor object for components that are not defined in the color space of its current color, and making such a request raises an exception. If you need a specific set of components, you should first convert the color to the appropriate color space using the colorUsingColorSpaceName: method. For more information, see “Converting Between Color Spaces” (page 71). Choosing Colors Applicationsthat need to present a color picker interface to the user can use either a color well or a color panel. A color well is a control that displays a single color. You can embed this control in your windows and use it to show a currently selected color. When clicked, a color well displays the system color panel, which provides an interface for picking a color. You can also use the color panel on its own to prompt the user for a color. For information about how to use color wells and the color panel in your application, see Color Programming Topics. Working with Color Spaces Colorspaces help your program maintain color fidelity throughout the creation and rendering process. Although most programs may never need to worry about color spaces, you might need to know the current color space in some situations, such as prior to manipulating color component values. Converting Between Color Spaces You can convert between color spaces using the colorUsingColorSpaceName: method of NSColor. This method creates a new color object representing the same color but using the color space you specify. To convert a color from RGB to CMYK, you could use code similar to the following: NSColor* rgbColor = [NSColor colorWithCalibratedRed:1.0 green: 0.5 blue: 0.5 alpha:0.75]; NSColor* cmykColor = [rgbColor colorUsingColorSpace:[NSColorSpace genericCMYKColorSpace]]; Color and Transparency Working with Color Spaces 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 71Mapping Physical Colors to a Color Space The range of colors (or gamut) that can be physically displayed on an output device differs from device to device. During rendering, Cocoa attempts to match the colors you specify in your code as closely as it can to the colors available in the target device. Sometimes, though, it maps colorsin a different way so asto emphasize different aspects of a color that might be more important when reproducing that color. The mapping used for colors is referred to as the rendering intent and it is something most developers rarely need to change. Because most developersshould not need to change the rendering intent, you cannotset the attribute directly from Cocoa. If your application needs more control over the color management, you must use Quartz to change the rendering intent. Table 4-2 lists the rendering intents supported by Quartz. Table 4-2 Quartz rendering intents Rendering intent Description Use the default rendering intent settings. In this mode, Quartz uses the relative colorimetric intent for all drawing except that ofsampled images; for sampled images, Quartz uses the perceptual rendering intent. kCGRenderingIntentDefault This rendering intent performs no white point adjustment to the colors. A color that appearsto be white on a screen display may be reproduced on a printed medium as a bluish color (because a white color on a screen actually has a bluish cast). This intent is useful for simulating one device on another or for rendering logos where exact color reproduction is important. kCGRenderingIntentAbsoluteColorimetric This rendering intent uses the white point information from the source and destination and adjusts the color information so that the white point of the source maps into the white point of the destination. In-gamut colors are also adjusted accordingly. This intent is typically used for line art graphics. kCGRenderingIntentRelativeColorimetric Thisrendering intent produces pleasing visual results and preservesthe relationship between colors at the expense of the absolute color reproduction. This intent is typically used for photographic images. kCGRenderingIntentPerceptual Thisrendering intent attemptsto maximize the saturation of colors. This intent is mostly used for business charts or graphics. kCGRenderingIntentSaturation To change the rendering intent, you must get a Quartz graphics context for the current drawing environment and call the CGContextSetRenderingIntent function, as shown in the following example: - (void) drawRect:(NSRect)rect Color and Transparency Working with Color Spaces 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 72{ CGContextRef theCG = [[NSGraphicsContext currentContext] graphicsPort]; // Change the rendering intent. CGContextSetRenderingIntent(theCG, kCGRenderingIntentPerceptual); // Draw your content. } Color and Transparency Working with Color Spaces 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 73Important: This chapter has not yet been updated to describe how images work in OS X v10.6. Significant changes were made to image processing in OS X v10.6. See Application Kit Release Notes (10.7 and Earlier) and High Resolution Guidelines for OS X for details. Images are an important part of any Mac app. In Cocoa, images play a very important, but flexible, role in your user interface. You can use imagesto render preexisting content or act as a buffer for your application's drawing commands. At the heart of Cocoa'simage manipulation code isthe NSImage class. This class manages everything related to image data and is used for the following tasks: ● Loading existing images from disk. ● Drawing image data into your views. ● Creating new images. ● Scaling and resizing images. ● Converting images to any of several different formats. You can use images in your program for a variety of tasks. You can load images from existing image files (such as JPEG, GIF, PDF, and EPS files) to draw elements of your user interface that might be too difficult (or too inefficient) to draw using primitive shapes. You can also use images as offscreen or temporary buffers and capture a sequence of drawing commands that you want to use at a later time. Although bitmaps are one of the most common types of image, it is important not to think of the NSImage class as simply managing photographic or bitmap data. The NSImage class in Cocoa is capable of displaying a variety of image types and formats. It provides support for photograph and bitmap data in many standard formats. It also provides support for vector, or command-based data, such as PDF, EPS, and PICT. You can even use the NSImage class to represent an image created with the Core Image framework. 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 74 ImagesImage Basics The NSImage class providesthe high-level interface for manipulating imagesin many different formats. Because it provides the high-level interface, NSImage knows almost nothing about managing the actual image data. Instead, the NSImage class manages one or more image representation objects—objects derived from the NSImageRep class. Each image representation object understands the image data for a particular format and is capable of rendering that data to the current context. The following sections provide insight into the relationship between image objects and image representations. Image Representations An image representation object represents an image at a specific size, using a specific color space, and in a specific data format. Image representations are used by an NSImage object to manage image data. An image representation object knows how to read image data from a file, write that data back to a file, and convert the image data to a raw bitmap that can then be rendered to the current context. Some image representations also provide an interface for manipulating the image data directly. For file-based images, NSImage creates an image representation object for each separate image stored in the file. Although most image formats support only a single image, formats such as TIFF allow multiple images to be stored. For example, a TIFF file might store both a full size version of an image and a thumbnail. If you are creating images dynamically, you are responsible for creating the image representation objects you need for your image. As with file-based images, most of the images you create need only a single image representation. Because NSImage is adept at scaling and adjusting images to fit the target canvas, it is usually not necessary to create different image representations at different resolutions. You might create multiple representations in the following situations, however: ● For printing, you might want to create a PDF representation or high-resolution bitmap of your image. ● You want to provide different content for your image when it is scaled to different sizes. When you draw an image, the NSImage object chooses the representation that is best suited for the target canvas. This choice is based on several factors, which are explained in “How an Image Representation Is Chosen” (page 77). If you want to ensure that a specific image representation is used, you can use the drawRepresentation:inRect: method of NSImage. Image Representation Classes Every image representation object is based on a subclass of NSImageRep. Cocoa defines several specific subclasses to handle commonly used formats. Table 5-1 lists the class and the image types it supports. Images Image Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 75Table 5-1 Image representation classes Supported Description types Class Handles bitmap data. Several common bitmap formats are supported directly. For custom image formats, you may have to decode the image data yourself before creating your image representation. An NSBitmapImageRep object uses any available color profile data (ICC or ColorSync) when rendering. TIFF, BMP, JPEG, GIF, PNG, DIB, ICO, among others NSBitmapImageRep This classis used internally by Cocoa to cache imagesfor drawing to the screen. You should not need to use this class directly. NSCachedImageRep Rendered data Provides a representation for a CIImage object, which itself supports most bitmap formats. NSCIImageRep N/A NSPDFImageRep PDF Handles the display of PDF data. Handles the display of PostScript or encapsulated PostScript data. NSEPSImageRep EPS Handles custom image data by passing it to a delegate object you provide. NSCustomImageRep Custom Handles the display of PICT format version 1, version 2, and extended version 2 pictures. The PICT format is a legacy format described in the Carbon QuickDraw Manager documentation. NSPICTImageRep PICT In most situations, you do not need to know how an image representation is created. For example, if you load an existing image from a file, NSImage automatically determines which type of image representation to create based on the file data. All you have to do is draw the image in your view. If you want to support new image formats, you can create a new image representation class. The NSImage class and its NSImageRep subclasses do not follow the class cluster model found in several other Cocoa classes. Creating new image representations is relatively straightforward and is explained in “Creating New Image Representation Classes” (page 109). Images Image Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 76How an Image Representation Is Chosen When you tell an NSImage object to draw itself, it searches its list of image representations for the one that best matches the attributes of the destination device. In determining which image representation to choose, it follows a set of ordered rules that compare the color space, image resolution, bit depth, and image size to the corresponding values in the destination device. The rules are applied in the following order: 1. Choose an image representation whose color space most closely matches the color space of the device. If the device is color, choose a color image representation. If the device is monochrome, choose a gray-scale image representation. 2. Choose an image representation that has at least as many pixels as the destination rectangle on both the horizontal and vertical axes. If no image representation matches exactly, choose the one that has more pixels than the destination. By default, any image representation with a resolution that’s an integer multiple of the device resolution is considered a match. If more than one representation matches, NSImage chooses the one that’s closest to the device resolution. You can force resolution matches to be exact by passing NO to the setMatchesOnMultipleResolution: method. You can force resolution matches to be exact on only one dimension by setting the setMatchesOnlyOnBestFittingAxis: property to YES. Thisrule prefers TIFF and bitmap representations, which have a defined resolution, over EPS representations, which do not. You can use the setUsesEPSOnResolutionMismatch: method to cause NSImage to choose an EPS representation in case a resolution match is not possible. 3. Choose a representation whose bit depth (bits per sample) matches the depth of the device. If no representation matches, choose the one with the highest number of bits per sample. You can change the order in which these rules are applied using the methods of NSImage. For example, if you want to invert the first and second rules, pass NO to the setPrefersColorMatch: method. Doing so causes NSImage to match the resolution before the color space. If these rules fail to narrow the choice to a single representation—for example, if the NSImage object has two color TIFF representations with the same resolution and depth—the chosen representation is operating-system dependent. Images and Caching The NSImage class incorporates an internal caching scheme aimed at improving your application’s drawing performance. This caching scheme is an important part of image management and is enabled by default for all image objects; however, you can change the caching optionsfor a particular image using the setCacheMode: method of NSImage. Table 5-2 lists the available caching modes. Images Image Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 77Table 5-2 Image caching modes Mode Description Use the default caching mode appropriate for the image representation. This is the default value. For more information, see Table 5-3 (page 78). NSImageCacheDefault NSImageCacheAlways Always caches a version of the image. Creates a cached version of the image if the size set for the image issmaller than the size of the actual image data. NSImageCacheBySize Does not cache the image. The image data is rasterized every time it is drawn. NSImageCacheNever Table 5-3 liststhe behavior of each image representation when its cache mode isset to NSImageCacheDefault. Table 5-3 Implied cache settings Image representation Cache behavior Behaves as if the NSImageCacheBySize setting were in effect. Creates a cached copy if the bitmap depth does not match the screen depth or if the bitmap resolution is greater than 72 dpi. NSBitmapImageRep NSCachedImageRep Not applicable. This class is used to implement caching. Behaves as if the NSImageCacheBySize setting were in effect. Creates a cached copy if the bitmap depth does not match the screen depth or if the bitmap resolution is greater than 72 dpi. NSCIImageRep NSPDFImageRep Behaves as if the NSImageCacheAlways setting were in effect. NSEPSImageRep Behaves as if the NSImageCacheAlways setting were in effect. NSCustomImageRep Behaves as if the NSImageCacheAlways setting were in effect. Behaves as if the NSImageCacheBySize setting were in effect. Creates a cached copy of the PICT image if it contains a bitmap whose depth does not match the screen depth or if that bitmap resolution is greater than 72 dpi. NSPICTImageRep Caching is a useful step toward preparing an image for display on the screen. When first loaded, the data for an image representation may not be in a format that can be rendered directly to the screen. For example, PDF data, when loaded into a PDF image representation, must be rasterized before it can be sent to the graphics card for display. With caching enabled, a NSPDFImageRep object rasterizes the PDF data before drawing it to Images Image Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 78the screen. The image representation then saves the raster data to alleviate the need to recreate it later. If you disable caching for such images, the rasterization process occurs each time you render the image, which can lead to a considerable performance penalty. For bitmap image representations, the decision to cache is dependent on the bitmap image data. If the bitmap’s colorspace, resolution, and bit depth match the corresponding attributesin the destination device, the bitmap may be used directly without any caching. If any of these attributes varies, however, the bitmap image representation may create a cached version instead. Important: It is important to remember that caching is aimed at improving performance during screen updates. During printing, Cocoa uses the native image data and resolution whenever possible and uses cached versions of the image only as a last resort. If you change the contents of an image representation object directly, you should invoke the recache method of the owning NSImage object when you are done and want the changes to be reflected on the screen. Cocoa does not automatically track the changes you make to your image representation objects. Instead, it continues to use the cached version of your image representation until you explicitly clear that cache using the recache method. Caching and Image Data Retention Because caching can lead to multiple copies of the image data in memory, NSImage usually dismisses the original image data once a cached copy is created. Dismissing the original image data saves memory and improves performance and is appropriate in situations where you do not plan on changing the image size or attributes. If you do plan on changing the image size or attributes, you may want to disable this behavior. Enabling data retention preventsimage degradation by basing changes on the original image data, as opposed to the currently cached copy. To retain image data for a specific image, you must send a setDataRetained: message to the NSImage object. Preferably, you should send this message immediately after creating the image object. If you send the message after rendering the image or locking focus on it, Cocoa may need to read the image data more than once. Caching Images Separately To improve performance, most caching of an application’s images occurs in one or more offscreen windows. These windows act as image repositories for the application and are not shared by other applications. Cocoa manages them automatically and assigns images to them based on the current image attributes. Images Image Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 79By default, Cocoa tries to reduce the number of offscreen windows by putting multiple images into a single window. For images whose size does not change frequently, this technique is usually faster than storing each image in its own window. For images whose size does change frequently, it may be better to cache the image separately by sending a setCachedSeparately: message to the image object. Image Size and Resolution Both NSImage and NSImageRep define methods for getting and setting the size of an image. The meaning of sizes can differ for each type of object, however. For NSImage, the size is always specified in units of the user coordinate space. Thus, an image that is 72 by 72 points is always rendered in a 1-inch square. For NSImageRep, the size is generally tied to the size of the native or cached bitmap. For resolution-independent image representations, a cached bitmap is created whose size matches that returned by NSImage. For true bitmap images, however, the size is equal to the width and height (in pixels) of the bitmap image. If you create your image from a data object or file, the NSImage object takes its image size information from the provided data. For example, with EPS data, the size is taken from the bounding rectangle, whereas with TIFF data, the size is taken from the ImageLength and ImageWidth fields. If you create a blank image, you must set the image size yourself when you initialize the NSImage object. You can change the size of an image at any time using the setSize: method of either NSImage or NSImageRep. The size returned by the NSImage version of the method representsthe dimensions of the image in the user coordinate space. Changing this value therefore changes the size of the image as it is drawn in one of your views. This change typically affects only the cached copy of the image data, if one exists. Changing the size of an image representation object changes the actual number of bits used to hold the image data. This change primarily affects bitmap images, and can result in a loss of data for your in-memory copy of the image. If the size of the data in an image representation is smaller than the rectangle into which it will be rendered, the image must be scaled to fit the target rectangle. For resolution-independent images, such as PDF images, scaling is less of an issue. For bitmap images, however, pixel values in the bitmap must be interpolated to fill in the extra space. Table 5-4 lists the available interpolation settings. Table 5-4 Image interpolation constants Interpolation constant Description NSImageInterpolationDefault Use the context’s default interpolation. NSImageInterpolationNone No interpolation. NSImageInterpolationLow Fast, low-quality interpolation. NSImageInterpolationHigh Slower, higher-quality interpolation. Images Image Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 80The preceding interpolation settings control both the quality and the speed of the interpolation algorithm. To change the currentinterpolation setting, use the setImageInterpolation:method of NSGraphicsContext. Note: Scaling affectsthe in-memory copy of image data only. It does not change data stored on-disk. With data retention disabled in an image, scaling the image multiple times can seriously degrade the resulting image quality. Making an image smaller through scaling is a lossy operation. If you subsequently make the image larger again by scaling, the results are based on the scaled-down version of the image. If you need several differentsizes of an image, you might want to create multiple image representation objects, one for each size, to avoid any lossy behavior. Alternatively, you can use the setDataRetained: method to ensure that the caching system has access to the original image data. Image Coordinate Systems Like views, NSImage objects use their own coordinate system to manage their content, which in this case is the image data itself. This internal coordinate system is independent of any containing views into which the image is drawn. Although you might think understanding this coordinate system is important for drawing images in your views, it actually is not. The purpose of the internal coordinate system is to orient the image data itself. As a result, the only time you should ever need to know about this internal coordinate system is when you create a new image by locking focus on an NSImage object and drawing into it. Image objects have two possible orientations: standard and flipped. When you create a new, empty NSImage object, you can set the orientation based on how you want to draw the image data. By default, images use the standard Cartesian (unflipped) coordinate system, but you can force them to use a flipped coordinate system by calling the setFlipped: method of NSImage prior to drawing. You must always set the image orientation before you lock focus on the image and start drawing though. Changing the orientation of the coordinate system after a lockFocus call has no effect. In addition, calling the setFlipped: method after you unlock focus again may not have the desired results and should be avoided. When drawing images in your view, you can think of the image as just a rectangle with some data in it. Regardless of the orientation of itsinternal coordinate system, you always place an image relative to the current view’s coordinate system. Figure 5-1 shows two images drawn in an unflipped view. The code used to draw Images Image Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 81each image uses the coordinate points shown in the figure, which are in the view’s (unflipped) coordinate system. Because the first image uses a flipped coordinate system internally, however, it drawsits content upside down. Figure 5-1 Image orientation in an unflipped view Drawing Versus Compositing The NSImage class offers different groups of methods to facilitate drawing your images to the current context. The two main groups of methods can be generally categorized asthe “drawing” versus“compositing” methods. There are three “drawing” methods of NSImage: ● drawAtPoint:fromRect:operation:fraction: ● drawInRect:fromRect:operation:fraction: ● drawRepresentation:inRect: The drawing methods are among the most commonly-used methods of NSImage because of their basic safety. Images are typically rendered in offscreen windows and then copied to the screen as needed. In some cases, several images may be composited into the same window for efficiency reasons. The draw methods use extra safety checking to ensure that only the contents of the current image are ever drawn in one of your views. The same is not true of compositing methods, of which there are the following: ● compositeToPoint:operation: ● compositeToPoint:fromRect:operation: ● compositeToPoint:fromRect:operation:fraction: ● compositeToPoint:operation:fraction: These methods can be more efficient than the drawing methods because they perform fewer checks on the image bounds. These methods do have other behaviors that you need to understand, however. The most important behavior is that the compositing methods undo any scale or rotation factors (but not translation Images Image Basics 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 82factors) applied to the CTM prior to drawing. If you are drawing in a flipped view or manually applied scaling or rotation valuesto the current context, these methods will ignore those transformations. Although this might seem like a problem, it actually can be a very useful tool. For example, if your program is scaling a graphic element, you might want to add a scale value to your transform to do the scaling (at least temporarily). If your element usesimage-based selection handles, you could use the compositing methodsto prevent those handles from being scaled along with the rest of your graphic element. The other thing to remember about the compositing methods is that none of them allow you to scale your image to a target rectangle. Cocoa composites the entire image (or designated portion thereof) bit-for-bit to the specified location. This is in contrast to the drawInRect:fromRect:operation:fraction: method, which lets you scale all or part of your image to the designated target rectangle in your view. Note: The dissolveToPoint:fraction: and dissolveToPoint:fromRect:fraction: methods behave in a similar manner asthe corresponding compositing methods. Their use is generally more limited though and better support for dissolving images is available through Core Image. Supported Image File Formats Cocoa supports many common image formats internally and can import image data from many more formats through the use of the Image I/O framework (ImageIO.framework). Basic Formats Table 5-5 lists the formats supported natively by Cocoa. (Uppercase versions of the filename extensions are also recognized.) Table 5-5 Cocoa supported file formats Format Filename extensions UTI Portable Document Format (PDF) .pdf com.adobe.pdf .eps, .epi, .epsf, .epsi, .ps Encapsulated PostScript (EPS) Tagged Image File Format (TIFF) .tiff, .tif public.tiff public.jpeg, public.jpeg-2000 Joint Photographic Experts Group .jpg, .jpeg, .jpe (JPEG), JPEG-2000 Graphic Interchange Format (GIF) .gif com.compuserve.gif Images Supported Image File Formats 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 83Format Filename extensions UTI Portable Network Graphic (PNG) .png public.png Macintosh Picture Format (PICT) .pict, .pct, .pic com.apple.pict Windows Bitmap Format (DIB) .bmp, .BMPf com.microsoft.bmp Windows Icon Format .ico com.microsoft.ico Icon File Format .icns com.apple.icns TIFF Compression TIFF images can be read from compressed data, aslong asthe compression algorithm is one of the fourschemes described in Table 5-6. Table 5-6 TIFF compression settings Compression Description Compresses and decompresses without information loss, achieving compression ratios up to 5:1. It may be somewhat slower to compress and decompress than the PackBits scheme. LZW Compresses and decompresses without information loss, but may not achieve the same compression ratios as LZW. PackBits JPEG JPEG compression is no longer supported in TIFF files, and this factor is ignored. Compresses and decompresses 1 bit gray-scale images using international fax compression standards CCITT3 and CCITT4. CCITTFAX An NSImage object can also produce compressed TIFF data using any of these schemes. To get the TIFF data, use the TIFFRepresentationUsingCompression:factor: method of NSImage. Support for Other File Formats In OS X v10.4 and later, NSImage supports many additional file formats using the Image I/O framework. To get a complete list of supported filename extensions, use the imageFileTypes class method of NSImage. The list of supported file formats continues to grow but Table 5-7 lists some of the more common formats that can be imported. Images Supported Image File Formats 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 84Table 5-7 Additional formats supported by Cocoa Type Filename extension Adobe RAW .dng Canon 2 RAW .cr2 Canon RAW .crw FlashPix .fpx, .fpix Fuji RAW .raf Kodak RAW .dcr MacPaint .ptng, .pnt, .mac Minolta RAW .mrw Nikon RAW .nef Olympus RAW .orf OpenEXR .exr Photoshop .psd QuickTime Import Format .qti, .qtif Radiance .hdr SGI .sgi Sony RAW .srf Targa .targa, .tga Windows Cursor .cur XWindow bitmap .xbm The Image I/O framework is part of Quartz, although the actual framework is part of the Application Services framework. Image I/O handles the importing and exporting of many file formats. To use Quartz directly, you read image data using the CGImageSourceRef opaque type and write using the CGImageDestinationRef type. For more information on using the Image I/O framework to read and write images, see CGImageSource Reference and CGImageDestination Reference . Images Supported Image File Formats 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 85Guidelines for Using Images Here are some guidelines to help you work with images more effectively: ● Use the NSImage interface whenever possible. The goal of NSImage is to simplify your interactions with image data. Working directly with image representations should be done only as needed. ● Treat NSImage and its image representations as immutable objects. The goal of NSImage is to provide an efficient way to display images on the target canvas. Avoid manipulating the data of an image representation directly, especially if there are alternatives to manipulating the data, such as compositing the image and some other content into a new image object. ● For screen-based drawing, it is best to use the built-in caching mechanism of NSImage. Using an NSCachedImageRep object is more efficient than an NSBitmapImageRep object with the same data. Cached image representations store image data using a CGImageRef object, which can be stored directly on the video card by Quartz. ● There is little benefit to storing multiple representations of the same image (possibly at different sizes) in a single NSImage. Modern hardware is powerful enough to resize and scale images quickly. The only reason to considerstoring multiple representationsisif each of those representations contains a customized version of the image or if your app supports high-resolution displays. ● If caching is enabled and you modify an image representation object directly, be sure to invoke the recache method of the owning NSImage object. Cocoa relies on cached content wherever possible to improve performance and does not automatically recreate its caches when you modify image representations. You must tell the image object to recreate its caches explicitly. ● Avoid recreating art that is already provided by the system. OS X makes several standard pieces of artwork available for inclusion in your own interfaces. This artwork ranges from standard icons to other elements you can integrate into your controls. You load standard images using the imageNamed: method. For a list of standard artwork, see the constants section in NSImage Class Reference . ● If your app supports high resolution displays, follow the guidelines in High Resolution Guidelines for OS X for providing and naming standard- and high-resolution versions of image resources. That document also outlines additions and changes to the NSImage class as of OS X v10.7.4. OS X defines several technologies for working with images. Although the NSImage class is a good general purpose class for creating, manipulating, and drawing images, there may be times when it might be easier or more efficient to use other imaging technologies. For example, rather than manually dissolving from one image to another by drawing partially transparent versions of each image over time, it would be more efficient to use Core Image to perform the dissolve operation for you. For information about other image technologies, and when you might use them, see “Choosing the Right Imaging Technology” (page 169). Images Guidelines for Using Images 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 86Creating NSImage Objects Before you can draw an image, you have to create or load the image data. Cocoa supports several techniques for creating new images and loading existing images. Loading an Existing Image For existing images, you can load the image directly from a file or URL using the methods of NSImage. When you open an image file, NSImage automatically creates an image representation that best matches the type of data in that file. Cocoa supports numerous file formats internally. In OS X v10.4 and later, Cocoa supports even more file formats using the Image I/O framework. For information on supported file types,see “Supported Image File Formats” (page 83). The following example shows how to load an existing image from a file. It is important to remember that images loaded from an existing file are intended primarily for rendering. If you want to manipulate the data directly, copy it to an offscreen window or other local data structure and manipulate it there. NSString* imageName = [[NSBundle mainBundle] pathForResource:@"image1" ofType:@"JPG"]; NSImage* tempImage = [[NSImage alloc] initWithContentsOfFile:imageName]; Loading a Named Image For frequently used images, you can use the Application Kit’s named image registry to load and store them. This registry provides a fast and convenient way to retrieve images without creating a new NSImage object each time. You can add images to this registry explicitly or you can use the registry itself to load known system or application-specific images, such as the following: ● System images stored in the Resources directory of the Application Kit framework ● Your application’s icon or other images located in the Resources directory of your main bundle. To retrieve images from the registry, you use the imageNamed: class method of NSImage. This method looks in the registry for an image associated with the name you provide. If none is found, it looks for the image among the Application Kit's shared resources. After that, it looks for a file in the Resources directory of your application bundle, and finally it checks the Application Kit bundle. If it finds an image file, it loads the image, adds it to the registry, and returns the corresponding NSImage object. As long as the corresponding image object is retained somewhere by your code, subsequent attempts to retrieve the same image file return the already-loaded NSImage object. Images Creating NSImage Objects 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 87To retrieve your application icon, ask for an image with the constant, NSImageNameApplicationIcon (on versions of OS X before v10.6, you can use the string @"NSApplicationIcon"). Your application's custom icon is returned, if it has one; otherwise, Cocoa returns the generic application icon provided by the system. For a list of image names you can use to load other standard system images, see the constants section in NSImage Class Reference . In addition to loading existing image files, you can also add images to the registry explicitly by sending a setName: message to an NSImage object. The setName: method adds the image to the registry under the designated name. You might use this method in cases where the image was created dynamically or is not located in your application bundle. Note: When adding images to the registry explicitly, choose a name that does not match the name of any image in your application bundle. If you choose a name that is used by a bundle resource, the explicitly added image supersedesthat resource. You can still load the resource using the methods of NSBundle, however. Drawing to an Image by Locking Focus It is possible to create images programmatically by locking focus on an NSImage object and drawing other images or paths into the image context. This technique is most useful for creating images that you intend to render to the screen, although you can also save the resulting image data to a file. Listing 5-1 shows you how to create a new empty image and configure it for drawing. When creating a blank image, you mustspecify the size of the new image in pixels. If you lock focus on an image that contains existing content, the new content is composited with the old content. When drawing, you can use any routines that you would normally use when drawing to a view. Listing 5-1 Drawing to an image NSImage* anImage = [[NSImage alloc] initWithSize:NSMakeSize(100.0, 100.0)]; [anImage lockFocus]; // Do your drawing here... [anImage unlockFocus]; // Draw the image in the current context. [anImage drawAtPoint:NSMakePoint(0.0, 0.0) Images Creating NSImage Objects 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 88fromRect: NSMakeRect(0.0, 0.0, 100.0, 100.0) operation: NSCompositeSourceOver fraction: 1.0]; Drawing to an image creates an NSCachedImageRep object or uses an existing cached image representation, if one exists. Even when you use the lockFocusOnRepresentation: method to lock onto a specific image representation, you do not lock onto the representation itself. Instead, you lock onto the cached offscreen window associated with that image representation. This behavior might seem confusing but reinforces the notion of the immutability of images and their image representations. Images and their representations are considered immutable for efficiency and safety reasons. If you consider the image files stored in your application bundle, would you really want to make permanent changes to the original image? Rather than change the original image data, NSImage and its image representations modify a copy of that data. Modifying a cached copy of the data is also more efficient forscreen-based drawing because the data is already in a format ready for display on the screen. Drawing Offscreen Images Using a Block-Based Drawing Method to Support High Resolution Displays If your app uses the lockFocus and unlockFocus methods of the NSImage class for offscreen drawing, consider using the method imageWithSize:flipped:drawingHandler: instead (available in OS X v10.8). If you use the lock focus methodsfor drawing, you can get unexpected results—either you’ll get a low resolution NSImage object that looks incorrect when drawn, or you’ll get a 2x image that has more pixels in its bitmap than you are expecting. Using the imageWithSize:flipped:drawingHandler: method ensures you’ll get correct results under standard and high resolution. The drawing handler is a block that can be invoked whenever the image is drawn to, and on whatever thread the drawing occurs. You should make sure that any state you access within the block is done in a thread-safe manner. The code in the block should be the same code that you would use between the lockFocus and unlockFocus methods. Creating a Bitmap There are a few different ways to create bitmaps in Cocoa. Some of these techniques are more convenient than others and some may not be available in all versions of OS X, so you should consider each one carefully. The following list summarizes the most common techniques and the situations in which you might use them: ● To create a bitmap from the contents of an existing CIImage object (in OS X v10.5 and later), use the initWithCIImage: method of NSBitmapImageRep. Images Creating NSImage Objects 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 89● To create a bitmap from the contents of a Quartz image (in OS X v10.5 and later), use the initWithCGImage: method of NSBitmapImageRep. When initializing bitmaps using this method, you should treat the returned bitmap as a read-only object. In addition, you should avoid accessing the bitmap data directly, as doing so requires the unpacking of the CGImageRef data into a separate set of buffers. ● To capture the contents of an existing view or image, use one of the following techniques: ● Lock focus on the desired object and use the initWithFocusedViewRect: method of NSBitmapImageRep. ● In OS X v10.4 and later, use the bitmapImageRepForCachingDisplayInRect: and cacheDisplayInRect:toBitmapImageRep:methods of NSView. The firstmethod creates a bitmap image representation suitable for use in capturing the view's contents while the second draws the view contents to the bitmap. You can reuse the bitmap image representation object to update the view contents periodically, as long as you remember to clear the old bitmap before capturing a new one. ● To draw directly into a bitmap, create a new NSBitmapImageRep object with the parameters you want and use the graphicsContextWithBitmapImageRep: method of NSGraphicsContext to create a drawing context. Make the new context the current context and draw. This technique is available only in OS X v10.4 and later. Alternatively, you can create an NSImage object (or an offscreen window), draw into it, and then capture the image contents. This technique is supported in all versions of OS X. ● To create the bitmap bit-by-bit, create a new NSBitmapImageRep object with the parameters you want and manipulate the pixels directly. You can use the bitmapData method to get the raw pixel buffer. NSBitmapImageRep also defines methods for getting and setting individual pixel values. This technique is the most labor intensive but gives you the most control over the bitmap contents. For example, you might use it if you want to decode the raw image data yourself and transfer it to the bitmap image representation. The sections that follow provide examples on how to use the first two techniques from the preceding list. For information on how to manipulate a bitmap, see NSBitmapImageRep Class Reference . Images Creating NSImage Objects 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 90Important: In many operating systems, offscreen bitmaps are used to buffer the actual content of a view or window. In OS X, you should generally not use offscreen bitmaps in this way. Most OS X windows are already double-buffered to prevent rendering artifacts caused by drawing during a refresh cycle. Adding your own offscreen bitmap would result in your window being triple-buffered, which is a waste of memory. Capturing the Contents of a View or Image A simple way to create a bitmap is to capture the contents of an existing view or image. When capturing a view, the view can either belong to an onscreen window or be completely detached and not onscreen at all. When capturing an image, Cocoa chooses the image representation that provides the best match for your target bitmap. Before attempting to capture the contents of a view, you should consider invoking the view’s canDraw method to see if the view should be drawn. Cocoa views return NO from this method in situations where the view is currently hidden or not associated with a valid window. If you are trying to capture the current state of a view, you might use the canDraw method to prevent your code from capturing the view when it is hidden. Once you have your view or image, lock focus on it and use the initWithFocusedViewRect: method of NSBitmapImageRep to capture the contents. When using this method, you specify the exact rectangle you want to capture from the view or image. Thus, you can capture all of the contents or only a portion; you cannot scale the content you capture. The initWithFocusedViewRect: method captures the bits exactly as they appear in the focused image or view. Listing 5-2 shows how to create a bitmap representation from an existing image. The example gets the image to capture from a custom routine, locks focus on it, and creates the NSBitmapImageRep object. Your own implementation would need to replace the call to myGetCurrentImage with the code to create or get the image used by your program. Listing 5-2 Capturing the contents of an existing image NSImage* image = [self myGetCurrentImage]; NSSize size = [image size]; [image lockFocus]; NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect: NSMakeRect(0,0,size.width,size.height)]; [image unlockFocus]; Images Creating NSImage Objects 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 91To capture the content of an onscreen view, you would use code very much like the preceding example. After locking focus on the view, you would create your NSBitmapImageRep object using the initWithFocusedViewRect: method. To capture the content of a detached (offscreen) view, you must create an offscreen window for the view before you try to capture its contents. The window object provides a backing buffer in which to hold the view’s rendered content. As long as you do not order the window onto the screen, the origin you specify for your window does not really matter. The example in Listing 5-3 uses large negative values for the origin coordinates (just to make sure the window is not visible) but could just as easily use the coordinate (0, 0). Listing 5-3 Drawing to an offscreen window NSRect offscreenRect = NSMakeRect(-10000.0, -10000.0, windowSize.width, windowSize.height); NSWindow* offscreenWindow = [[NSWindow alloc] initWithContentRect:offscreenRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreRetained defer:NO]; [offscreenWindow setContentView:myView]; [[offscreenWindow contentView] display]; // Draw to the backing buffer // Create the NSBitmapImageRep [[offscreenWindow contentView] lockFocus]; NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect: NSMakeRect(0, 0, windowSize.width, windowSize.height)]; // Clean up and delete the window, which is no longer needed. [[offscreenWindow contentView] unlockFocus]; [offscreenWindow release]; Drawing Directly to a Bitmap In OS X v10.4 and later, it is possible to create a bitmap image representation object and draw to it directly. This technique is simple and does not require the creation of any extraneous objects, such as an image or window. If your code needs to run in earlier versions of OS X, however, you cannot use this technique. Images Creating NSImage Objects 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 92Listing 5-4, creates a new NSBitmapImageRep object with the desired bit depth, resolution, and color space. It then creates a new graphics context object using the bitmap and makes that context the current context. Listing 5-4 Drawing directly to a bitmap NSRect offscreenRect = NSMakeRect(0.0, 0.0, 500.0, 500.0); NSBitmapImageRep* offscreenRep = nil; offscreenRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil pixelsWide:offscreenRect.size.width pixelsHigh:offscreenRect.size.height bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace bitmapFormat:0 bytesPerRow:(4 * offscreenRect.size.width) bitsPerPixel:32]; [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep]]; // Draw your content... [NSGraphicsContext restoreGraphicsState]; Once drawing is complete, you can add the bitmap image representation object to an NSImage object and display it like any other image. You can use this image representation object as a texture in your OpenGL code or examine the bits of the bitmap using the methods of NSBitmapImageRep. Creating a PDF or EPS Image Representation The process for creating an image representation for PDF or EPS data is the same for both. In both cases, you use a custom NSView object together with the Cocoa printing system to generate the desired data. From the generated data, you then create an image representation of the desired type. Images Creating NSImage Objects 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 93The NSView class defines two convenience methods for generating data based on the contents of the view: ● For PDF data, use the dataWithPDFInsideRect: method of NSView. ● For EPS data, use the dataWithEPSInsideRect: method of NSView. When you send one of these messages to your view, Cocoa launches the printing system, which drives the data generation process. The printing system handles most of the data generation process,sending appropriate messages to your view object as needed. For example, Cocoa sends a drawRect: message to your view for each page that needs to be drawn. The printing system also invokes other methods to compute page ranges and boundaries. Note: The NSView class provides a default pagination scheme. To provide a custom scheme, your view must override the knowsPageRange: and rectForPage: methods at a minimum. For more information about printing and pagination, see Printing Programming Guide for OS X . After the printing system finishes, the code that called either dataWithPDFInsideRect: or dataWithEPSInsideRect: receives an NSData object with the PDF or EPS data. You must then pass this object to the imageRepWithData: method of either NSEPSImageRep or NSPDFImageRep to initialize a new image representation object, which you can then add to your NSImage object. Listing 5-5 shows the basic steps for creating a PDF image from some view content. The view itself must be one that knows how to draw the desired content. This can be a detached view designed solely for drawing the desired content with any desired pagination, or it could be an existing view in one of your windows. Listing 5-5 Creating PDF data from a view MyPDFView* myView = GetMyPDFRenderView(); NSRect viewBounds = [myView bounds]; NSData* theData = [myView dataWithPDFInsideRect:viewBounds]; NSPDFImageRep* pdfRep = [NSPDFImageRep imageRepWithData:theData]; // Create a new image to hold the PDF representation. NSImage* pdfImage = [[NSImage alloc] initWithSize:viewBounds.size]; [pdfImage addRepresentation:pdfRep]; Images Creating NSImage Objects 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 94If you choose to use an existing onscreen view, your view’s drawing code should distinguish between content drawn for the screen or for the printing system and adjust content accordingly. Use the currentContextDrawingToScreen class method or the isDrawingToScreen instance method of NSGraphicsContext to determine whether the current context is targeted for the screen or a print-based canvas. These methods return NO for operations that generate PDF or EPS data. Important: When drawing in a printing context, the only supported compositing operators are NSCompositeCopy and NSCompositeSourceOver. If you need to render content using any other operators, you must composite them to an image or offscreen window first and then render the resulting image to the printing context using one of the supported operators. Using a Quartz Image to Create an NSImage The NSImage class does not provide any direct means for wrapping data from a Quartz image object. If you have a CGImageRef object, the simplest way to create a corresponding Cocoa image is to lock focus on an NSImage object and draw yourQuartz image using the CGContextDrawImage function. The basic techniques for how to do this are covered in “Drawing to an Image by Locking Focus” (page 88). Working with Images Once you have an image, there are many ways you can use it. The simplest thing you can do is draw it into a view as part of your program’s user interface. You can also process the image further by modifying it in any number of ways. The following sections show you how to perform several common tasks associated with images. Drawing Images into a View The NSImage class defines several methods for drawing an image into the current context. The two most commonly used methods are: ● drawAtPoint:fromRect:operation:fraction: ● drawInRect:fromRect:operation:fraction: These methods offer a simple interface for rendering your images, but more importantly, they ensure that only your image content is drawn. Other methods, such as the compositeToPoint:operation: method and its variants, are fast at drawing images but they do not check the image’s boundaries before drawing. If the drawing rectangle strays outside of the image bounds, it is possible to draw content not belonging to your Images Working with Images 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 95image. If the image resides on a shared offscreen window, which many do, it is even possible to draw portions of other images. For more information about the differences between these methods, see “Drawing Versus Compositing” (page 82). With one exception, all of the drawing and compositing methods choose the image representation that is best suited for the target canvas—see “How an Image Representation Is Chosen” (page 77). The one exception is the drawRepresentation:inRect: method, which uses the image representation object you specify. For more information about the use of these methods, see the NSImage reference. Images support the same set of compositing options as other Cocoa content, with the same results. For a complete list of compositing options and an illustration of their effects,see “Setting Compositing Options” (page 32). Drawing Resizable Textures Using Images If you are implementing a resizable custom control and want the control to have a textured background that does not distort as the control is resized, you would typically break up the background portion into several different images and composite them together. Although some of the images would contain fixed size content, others would need to be designed to present a smooth texture even after being resized or tiled. When it comes time to draw the images, however, you should avoid doing the drawing yourself. Instead, you should use the following AppKit functions, which were introduced in OS X v10.5: ● NSDrawThreePartImage ● NSDrawNinePartImage Drawing multipart images cleanly on high-resolution screens can be very challenging. If you are not careful about aligning images correctly on integral boundaries, the resulting texture might contain pixel cracks or other visual artifacts. The AppKit functionstake into account all of the factorsrequired to draw multipart images correctly in any situation, including situations where resolution independence scale factors other than 1.0 are in use. Figure 5-2 shows how you assemble a three-part image for a horizontally resizable control. The two end caps are fixed size images that provide the needed decoration for the edges of the background. The center fill portion then resizes appropriately to fit the bounding rectangle you pass into the NSDrawThreePartImage Images Working with Images 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 96function. (If you wanted the control to be resizable in the vertical direction, you would stack these images vertically instead of horizontally.) After drawing the background with this function, you would then layer any additional content on top of the background as needed. Figure 5-2 Drawing a three-part image Figure 5-3 shows you how to assemble a nine-part image for a control that can be resized both vertically and horizontally. In this case, the size of the corner pieces stays fixed but the five remaining fill images vary in size to fit the current bounding rectangle. Figure 5-3 Drawing a nine-part image For more information about these functions, see their descriptions in Application Kit Functions Reference . Images Working with Images 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 97Creating an OpenGL Texture In OpenGL, a texture is one way to paint the surface of an object. For complex or photorealistic surfaces, it may be easier to apply a texture than render the same content using primitive shapes. Almost any view or image in Cocoa can be used to create an OpenGL texture. From a view or image, you create a bitmap image representation object (as described in “Capturing the Contents of a View or Image” (page 91)) and then use that object to create your texture. Listing 5-6 shows a self-contained method for creating a texture from an NSImage object. After creating the NSBitmapImageRep object, this method configures some texture-related parameters, creates a new texture object, and then associates the bitmap data with that object. This method handles 24-bit RGB and 32-bit RGBA images, but you could readily modify it to support other image formats. You must pass in a pointer to a valid GLuint variable for texName but the value stored in that parameter can be 0. If you specify a nonzero value, your identifier is associated with the texture object and can be used to identify the texture later; otherwise, an identifier is returned to you in the texName parameter. Listing 5-6 Creating an OpenGL texture from an image - (void)textureFromImage:(NSImage*)theImg textureName:(GLuint*)texName { NSBitmapImageRep* bitmap = [NSBitmapImageRep alloc]; int samplesPerPixel = 0; NSSize imgSize = [theImg size]; [theImg lockFocus]; [bitmap initWithFocusedViewRect: NSMakeRect(0.0, 0.0, imgSize.width, imgSize.height)]; [theImg unlockFocus]; // Set proper unpacking row length for bitmap. glPixelStorei(GL_UNPACK_ROW_LENGTH, [bitmap pixelsWide]); // Set byte aligned unpacking (needed for 3 byte per pixel bitmaps). glPixelStorei (GL_UNPACK_ALIGNMENT, 1); // Generate a new texture name if one was not provided. if (*texName == 0) glGenTextures (1, texName); Images Working with Images 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 98glBindTexture (GL_TEXTURE_RECTANGLE_EXT, *texName); // Non-mipmap filtering (redundant for texture_rectangle). glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR); samplesPerPixel = [bitmap samplesPerPixel]; // Nonplanar, RGB 24 bit bitmap, or RGBA 32 bit bitmap. if(![bitmap isPlanar] && (samplesPerPixel == 3 || samplesPerPixel == 4)) { glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, samplesPerPixel == 4 ? GL_RGBA8 : GL_RGB8, [bitmap pixelsWide], [bitmap pixelsHigh], 0, samplesPerPixel == 4 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, [bitmap bitmapData]); } else { // Handle other bitmap formats. } // Clean up. [bitmap release]; } In the preceding code, there are some additional points worth mentioning: ● GL_TEXTURE_RECTANGLE_EXT is used for non–power-of-two texture support, which is not supported on the Rage 128 hardware. ● The gluScaleImage() function can be used to scale non-PoT texturesinto PoT dimensionsfor hardware that doesn't support GL_TEXTURE_RECTANGLE_EXT. ● When you call this method, the current context must be a valid OpenGL context. For more information about OpenGL graphics contexts, see “Using OpenGL in Your Application” (page 165). Images Working with Images 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 99● Upon completion, the texture is bound to the value in texName. If you specified 0 for the texName parameter, a new texture ID is generated for you and returned in texName. For more information on Apple's support for OpenGL, see OpenGL Programming Guide for Mac . Applying Core Image Filters In OS X v10.4 and later, Core Image filters are a fast and efficient way to modify an image without changing the image itself. Core Image filters use graphics acceleration to apply real-time effects such as Gaussian blurs, distortions, and color corrections to an image. Because the filters are applied when content is composited to the screen, they do not modify the actual image data. Core Image filters operate on CIImage objects. If you have an existing CIImage object, you can simply apply any desired filtersto it and use it to create an NSCIImageRep object. You can then add thisimage representation object to an NSImage object and draw the results in your view. In OS X v10.5 and later, you can also use the initWithCIImage: method of NSBitmapImageRep to render already-processed images directly to a bitmap representation. If you do not already have a CIImage object, you need to create one using your program’s existing content. The first step is to create a bitmap image representation for the content you want to modify, the process for which is described in “Creating a Bitmap” (page 89). Once you have an NSBitmapImageRep object, use the initWithBitmapImageRep: method of CIImage to create a Core Image image object. For information on how to apply Core Image filters to a CIImage object, see “Using Core Image Filters” in Core Image Programming Guide . Getting and Setting Bitmap Properties Every NSBitmapImageRep object contains a dictionary that defines the bitmap’s associated properties. These properties identify important information about the bitmap, such as how it was compressed, its color profile (if any), its current gamma level, its associated EXIF data, and so on. When you create a new NSBitmapImageRep from an existing image file, many of these properties are set automatically. You can also access and modify these properties using the valueForProperty: and setProperty:withValue: methods of NSBitmapImageRep. For a complete list of properties you can get and set for a bitmap, see NSBitmapImageRep Class Reference . Converting a Bitmap to a Different Format The NSBitmapImageRep class provides built-in support for converting bitmap data to severalstandard formats. To convert bitmap images to other formats, you can use any of the following methods: Images Working with Images 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 100● +TIFFRepresentationOfImageRepsInArray: ● +TIFFRepresentationOfImageRepsInArray:usingCompression:factor: ● -TIFFRepresentation ● -TIFFRepresentationUsingCompression:factor: ● +representationOfImageRepsInArray:usingType:properties: ● -representationUsingType:properties: The first set of methods generate TIFF data for the bitmap. For all other supported formats, you use the representationOfImageRepsInArray:usingType:properties: and representationUsingType:properties: methods. These methods support the conversion of bitmap data to BMP, GIF, JPEG, PNG, and TIFF file formats. All of the preceding methods return an NSData object with the formatted image data. You can write this data out to a file or use it to create a newNSBitmapImageRep object. Associating a Custom Color Profile With an Image You can associate a custom ColorSync profile with a NSBitmapImageRep object containing pixel data produced by decoding a TIFF, JPEG, GIF or PNG file. To associate the data with the bitmap image representation, you use the setProperty:withValue: method of NSBitmapImageRep and the NSImageColorSyncProfileData property. Listing 5-7 shows an example of how to load the ColorSync data and associate it with a bitmap image representation. Listing 5-7 Adding a ColorSync profile to an image @implementation NSBitmapImageRep (MoreColorMethods) - (NSBitmapImageRep *) imageRepWithProfileAtPath:(NSString *) pathToProfile { id result = [self copy]; // Build an NSData object using the specified ColorSync profile id profile = [NSData dataWithContentsOfFile: pathToProfile]; // Set the ColorSync profile for the object [result setProperty:NSImageColorSyncProfileData withValue:profile]; return [result autorelease]; Images Working with Images 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 101} @end In OS X v10.5, it is also possible to associate a custom ICC color profile with an NSBitmapImageRep object. To do so, you must initialize your NSBitmapImageRep instance using the calibrated RGB colorspace (NSCalibratedRGBColorSpace). After that, you load the profile and associate the corresponding data object with the NSImageColorSyncProfileData key exactly as you would for a ColorSync profile. Converting Between Color Spaces Cocoa does not provide any direct ways to convert images from one color space to another. Although Cocoa fully supports color spaces included with existing image files, there is no way to convert image data directly using NSImage. Instead, you must use a combination of Quartz and Cocoa to convert the image data. Creating the Target Image Converting the color space of an existing image requires the use of Quartz to establish a drawing context that uses the target color space. Once you have a CGContextRef object with the desired color space, you can use it to configure the Cocoa drawing environment and draw your image. Listing 5-8 shows you how to create a Quartz bitmap context using a custom colorspace. Thisfunction receives a CMProfileRef object, which you can get from the ColorSync Manager or from the colorSyncProfile method of NSColorSpace. It uses the color profile to determine the number of channels in the color space. Once it knows the total number of channels (including alpha) needed for the bitmap, it creates and returns a matching bitmap context. Listing 5-8 Creating a bitmap with a custom color profile CGContextRef CreateCGBitmapContextWithColorProfile(size_t width, size_t height, CMProfileRef profile, CGImageAlphaInfo alphaInfo) { size_t bytesPerRow = 0; size_t alphaComponent = 0; // Get the type of the color space. CMAppleProfileHeader header; Images Working with Images 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 102if (noErr != CMGetProfileHeader(profile, &header)) return nil; // Get the color space info from the profile. CGColorSpaceRef csRef = CGColorSpaceCreateWithPlatformColorSpace(profile); if (csRef == NULL) return NULL; // Add 1 channel if there is an alpha component. if (alphaInfo != kCGImageAlphaNone) alphaComponent = 1; // Check the major color spaces. OSType space = header.cm2.dataColorSpace; switch (space) { case cmGrayData: bytesPerRow = width; // Quartz doesn’t support alpha for grayscale bitmaps. alphaInfo = kCGImageAlphaNone; break; case cmRGBData: bytesPerRow = width * (3 + alphaComponent); break; case cmCMYKData: bytesPerRow = width * 4; // Quartz doesn’t support alpha for CMYK bitmaps. alphaInfo = kCGImageAlphaNone; break; default: Images Working with Images 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 103return NULL; } // Allocate the memory for the bitmap. void* bitmapData = malloc(bytesPerRow * height); CGContextRef theRef = CGBitmapContextCreate(bitmapData, width, height, 8, bytesPerRow, csRef, alphaInfo); // Cleanup if an error occurs; otherwise, the caller is responsible // for releasing the bitmap data. if ((!theRef) && bitmapData) free(bitmapData); CGColorSpaceRelease(csRef); return theRef; } Once you have a Quartz bitmap context, you can create a new Cocoa graphics context object and use it for drawing. To create the NSGraphicsContext object, you use the graphicsContextWithGraphicsPort:flipped: method, which takes a CGContextRef object as a parameter. You then use the setCurrentContext: method to make it current and begin drawing. When you are done drawing, you use Quartz to create a CGImageRef object containing the results. Listing 5-9 shows this process. Listing 5-9 Converting a bitmap to a different color space - (CGImageRef) convertBitmapImageRep:(NSBitmapImageRep*)theRep toColorSpace:(NSColorSpace*)colorspace { if (!theRep) return nil; // Map the Cocoa constants returned by -bitmapFormat to their // Quartz equivalents. Images Working with Images 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 104CGImageAlphaInfo alphaInfo = GetAlphaInfoFromBitmapImageRep(theRep); // Get the rest of the image info. NSSize imageSize = [theRep size]; size_t width = imageSize.width; size_t height = imageSize.height; CMProfileRef profile = (CMProfileRef)[colorspace colorSyncProfile]; // Create a new 8-bit bitmap context based on the image info. CGContextRef cgContext = CreateCGBitmapContextWithColorProfile(width, height, profile, alphaInfo); if (cgContext == NULL) return NULL; // Create an NSGraphicsContext that draws into the CGContext. NSGraphicsContext *graphicsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:cgContext flipped:NO]; // Make the NSGraphicsContext current and draw into it. [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext:graphicsContext]; // Create a new image for rendering the original bitmap. NSImage* theImage = [[[NSImage alloc] initWithSize:imageSize] autorelease]; [theImage addRepresentation:theRep]; // Draw the original image in the Quartz bitmap context. NSRect imageRect = NSMakeRect(0.0, 0.0, imageSize.width, imageSize.height); [theImage drawAtPoint:NSMakePoint(0.0, 0.0) fromRect:imageRect operation: NSCompositeSourceOver fraction: 1.0]; [NSGraphicsContext restoreGraphicsState]; Images Working with Images 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 105// Create a CGImage from the CGContext's contents. CGImageRef cgImage = CGBitmapContextCreateImage(cgContext); // Release the context. Note that this does not release the bitmap data. CGContextRelease(cgContext); return cgImage; } There are two ways to get an NSImage object from a CGImageRef type. In OS X v10.5 and later, you can create an NSBitmapImageRep object using its initWithCGImage: method and then add that image representation to an NSImage object. If your code needs to run in versions of OS X v10.4 or earlier, however, you can lock focus on an NSImage object and use the CGContextDrawImage function to draw the Quartz image into the image. This latter technique creates a copy of the image data and requires more effort than using the initWithCGImage: method but is available on all versions of OS X. Listing 5-10 shows a sample method that demonstrates both approaches but always uses the best approach available for the target platform. Listing 5-10 Using a CGImageRef object to create an NSImage object - (NSImage*)imageFromCGImageRef:(CGImageRef)image { NSImage* newImage = nil; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 NSBitmapImageRep* newRep = [[NSBitmapImageRep alloc] initWithCGImage:image]; NSSize imageSize; // Get the image dimensions. imageSize.height = CGImageGetHeight(image); imageSize.width = CGImageGetWidth(image); newImage = [[NSImage alloc] initWithSize:imageSize]; [newImage addRepresentation:newRep]; #else Images Working with Images 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 106NSRect imageRect = NSMakeRect(0.0, 0.0, 0.0, 0.0); CGContextRef imageContext = nil; // Get the image dimensions. imageRect.size.height = CGImageGetHeight(image); imageRect.size.width = CGImageGetWidth(image); // Create a new image to receive the Quartz image data. newImage = [[NSImage alloc] initWithSize:imageRect.size]; [newImage lockFocus]; // Get the Quartz context and draw. imageContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; CGContextDrawImage(imageContext, *(CGRect*)&imageRect, image); [newImage unlockFocus]; #endif return [newImage autorelease]; } Using a Custom Color Profile If you have an existing ICC profile and want to associate that profile with an image, you must do so using the ColorSync Manager. If you are working with Quartz graphic contexts, you use the ICC profile to obtain the color space information needed to create a CGImageRef object. You can then use that color space information to create an appropriate context for rendering your image. Listing 5-11 shows you how to create a CGColorSpaceRef object from an ICC profile. This code uses several ColorSync Manager functions to create a CMProfileRef object, from which you can then extract the color space object. OS X includes several standard ICC profiles in the /System/Library/ColorSync/Profiles/ directory. Listing 5-11 Creating a color space from a custom color profile CGColorSpaceRef CreateColorSpaceForProfileAtPath(NSString* path) { Images Working with Images 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 107CMProfileLocation profileLoc; CMProfileRef profileRef; CGColorSpaceRef csRef = NULL; // Specify where the ICC profile data file is located. profileLoc.locType = cmPathBasedProfile; strncpy(profileLoc.u.pathLoc.path, [path fileSystemRepresentation], 255); // Get the ColorSync profile information from the data file. CMOpenProfile(&profileRef, &profileLoc); // Use the profile to create the color space object. csRef = CGColorSpaceCreateWithPlatformColorSpace(profileRef); CMCloseProfile(profileRef); return csRef; } For more information on ColorSync and its functions, see ColorSync Manager Reference . Premultiplying Alpha Values for Bitmaps Although premultiplying alpha values used to be a common way to improve performance when rendering bitmaps, the technique is not recommended for programsrunning inOS X. Premultiplication involves multiplying values in the bitmap’s alpha channel with the corresponding pixel values and storing the results back to the bitmap’s source file. The goal of pre-multiplication is to reduce the number of calculations performed when the bitmap is composited with other content. In OS X, premultiplication can actually result in more calculations. In OS X, color correction is integral to the operating system. In order to process colors correctly, ColorSync needs the original pixel color values. If a bitmap contains premultiplied color values, ColorSync must undo the premultiplication before it can check the colors. This extra step adds a significant amount of work to the system because it must be performed every time the colors are checked. Images Working with Images 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 108The only reason to consider premultiplication of alpha values for your bitmaps is if your data is already premultiplied and leaving it that way is beneficial to your program’s data model. Even so, you should do some performance tests to see if using premultiplied bitmaps hurts your overall application performance. Cocoa incorporates color management into many parts of the framework. If your code paths use these parts of the framework, you might find it beneficial to change your model. Creating New Image Representation Classes If you want to add support for new image formats or generate images from other types of source information, you may want to subclass NSImageRep. Although Cocoa supports many image formats directly, and many more indirectly through the Image IO framework,subclassing NSImageRep gives you control over the handling of image data while at the same time maintaining a tight integration with the NSImage class. If you decide to subclass, you should provide implementations for the following methods: ● imageUnfilteredTypes ● canInitWithData: ● initWithData: ● draw These methods provide the basic interface that the parent NSImageRep class needs to interact with your subclass. The methods provide information about what image data formats your class supports along with entry points for initializing your object and drawing the image. Before your subclass can be used, it must be registered with the Application Kit. You should do this early in your application’s execution by invoking the registerImageRepClass: class method of NSImageRep. Registering your class lets Cocoa know that your class exists and that it can handle a specific set of file types. Yourimplementation ofthe imageUnfilteredTypesmethod should return an array ofUTItypes corresponding to the image file types your class supports directly. Another method you should always override is the canInitWithData: method. Once your image representation class has been identified as handling a particular type of data, Cocoa may notify it when data of the appropriate type is received. At that time, Cocoa passes a data object to your canInitWithData: method. Your implementation of this method should examine the data quickly and verify that it can really handle the format. Images Creating New Image Representation Classes 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 109Note: If your subclass is capable of reading multiple images from a single file, you should also implement the imageRepsWithData: method. This method must parse the image data and check to see if it indeed contains multiple images. For each separate image, you should create an instance of your subclass and initialize it with the appropriate subset of the image data. Once your class is chosen to handle the image data, Cocoa looks for an initWithData: method and uses it to initialize your object with the image data. Your implementation of this method should retain the data and use it to initialize the object. At some point later, your draw method may be called to render the data in the current context. Your draw method should render the data at the current origin point and with the current size and settings specified by the NSImageRep parent class. Images Creating New Image Representation Classes 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 110Creating an effective and beautiful Mac app often requires the use of many different techniques. Beyond the basic drawing of paths and images in views, there are other ways to create more complex imagery for your application. The following sections cover many of the most commonly used techniques supported by Cocoa. Adding Shadows to Drawn Paths Cocoa provides support for shadows through the NSShadow class. A shadow mimics a light source cast on the object, making paths appear as if they’re floating above the surface of the view. Figure 6-1 shows the effect created by a shadow for a few paths. Figure 6-1 Shadows cast by rendered paths A shadow effect consists of horizontal and vertical offset values, a blur value, and the shadow color. These effects combine to give the illusion that there is a light above the canvas that is shining down on the shapes below. The offset and blur values effectively determine the position of the light and the height of the shapes above the canvas. 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 111 Advanced Drawing TechniquesShadow positions always use the base coordinate system of the view, ignoring any transforms you apply to the shapes in your view. This means that no matter how you manipulate the shapes in a view, the apparent position of the light generating the shadows never changes. If you want to change the apparent position of the light, you must change the shadow object attributes and apply the updated shadow object to the current graphics context before drawing your content. To create a shadow, you create an NSShadow object and call its methods to set the desired shadow attributes. If you anticipate one or more paths overlapping each other, you should be sure to choose a color that has an alpha value; otherwise, shadows that intersect other objects might look flat and ruin the effect. To apply the shadow, invoke its set method. Listing 6-1 shows the code used to create the shadow for the paths in Figure 6-1 (page 111). A partially transparent color is used to allow for overlapping paths and shadows. Listing 6-1 Adding a shadow to a path [NSGraphicsContext saveGraphicsState]; // Create the shadow below and to the right of the shape. NSShadow* theShadow = [[NSShadow alloc] init]; [theShadow setShadowOffset:NSMakeSize(10.0, -10.0)]; [theShadow setShadowBlurRadius:3.0]; // Use a partially transparent color for shapes that overlap. [theShadow setShadowColor:[[NSColor blackColor] colorWithAlphaComponent:0.3]]; [theShadow set]; // Draw your custom content here. Anything you draw // automatically has the shadow effect applied to it. [NSGraphicsContext restoreGraphicsState]; [theShadow release]; Shadow effects are stored as part of the graphics state, so once set, they affect all subsequent rendering commands in the current context. This is an important thing to remember because it might force you to think about the order in which you draw your content. For example, if you set up a shadow, fill a path, and then Advanced Drawing Techniques Adding Shadows to Drawn Paths 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 112stroke the same path, you do not get a single shape with an outline, fill color, and shadow. Instead, you get two shapes—an outline and a fill shape—and two shadows, one for each shape. If you stroke the path after filling it, the shadow for the stroked path appears on top of the filled shape. In Figure 6-1 (page 111), the desired effect was achieved by applying the shadow to only the fill shape of each path. Note: Another way to a single shadow for multiple paths is using a Quartz transparency layer. For more information about using transparency layers, see Quartz 2D Programming Guide . Creating Gradient Fills A gradient fill (also referred to as a shading in Quartz) is a pattern that gradually changes from one color to another. Unlike the image-based patterns supported by NSColor, a gradient fill does not tile colors to fill the target shape. Instead, it uses a mathematical function to compute the color at individual points along the gradient. Because they are mathematical by nature, gradients are resolution independent and scale readily to any device. Figure 6-2 shows some simple gradient fill patterns. Gradients a and b show linear gradients filling different Bezier shapes and aligned along different angles while gradients c and d show radial gradients. In the case of gradient c, the gradient was set to draw before and after the gradient’s starting and ending locations, thus Advanced Drawing Techniques Creating Gradient Fills 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 113creating both a white circle in the very center of the gradient and a black border surrounding the gradient. For gradient d, the center points of the circles used to draw the gradient are offset, creating a different sort of shading effect. Figure 6-2 Different types of gradients In OS X v10.5 and later, Cocoa provides support for drawing gradients using the NSGradient class. If your software runs on earlier versions of OS X, you must use Quartz or Core Image to perform gradient fills. Using the NSGradient Class In OS X v10.5 and later, you can use the NSGradient class to create complex gradient fill patterns without having to write your own color computation function. Gradient objects are immutable objects that store information about the colors in the gradient and provide an interface for drawing those colors to the current context. When you create an NSGradient object, you specify one or more NSColor objects and a set of optional location parameters. During drawing, the gradient object uses this information to compute the color transitions for the gradient. Advanced Drawing Techniques Creating Gradient Fills 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 114The NSGradient class supports both high-level and primitive drawing methods. The high-level methods provide a simple interface for drawing gradients as a fill pattern for a Bezier path or rectangle. If you need additional control over the final shape and appearance of the gradient fill, you can set up the clipping path your self and use the primitive drawing methods of NSGradient to do your drawing. Configuring the Colors of a Gradient Object The NSGradient class uses color stops to determine the position of color changes in its gradient fill. A color stop is a combination of an NSColor object and a floating-point number in the range 0.0 to 1.0. The floating point number represents the relative position of the associated color along the drawing axis of the gradient, which can be either radial or axial. By definition, gradients must have at least two color stops. Typically, these color stops represent the start and end points of the gradient. Although the start point is often located at 0.0 and the end point at 1.0, that may not always be the case. You can position the start and end points anywhere along the gradient’s drawing axis. As it creates the gradient, the gradient object fills the area prior to the start point with the start color and similarly fills the area after the end point with the end color. You can use the same gradient object to draw multiple gradient fills and you can freely mix the creation of radial and axial gradients using the same gradient object. Although you configure the colors of a gradient when you create the gradient object, you configure the drawing axis of the gradient only when you go to draw it. The NSGradient class definesthe following methodsfor configuring the colors and colorstops of a gradient. ● initWithStartingColor:endingColor: ● initWithColors: ● initWithColorsAndLocations: ● initWithColors:atLocations:colorSpace: Although you cannot change the colors of a gradient object after you initialize it, you can get information about the colors it contains using accessor methods. The numberOfColorStops method returns the number of colors that the gradient uses to draw itself and the getColor:location:atIndex: method retrieves the colorstop information for each of those colors. If you want to know what color would be drawn for the gradient in between two color stops, you can use the interpolatedColorAtLocation: method to get it. Drawing to a High-Level Path The NSGradient class defines several convenience methods for drawing both radial and axial gradients: ● drawInRect:angle: ● drawInRect:relativeCenterPosition: ● drawInBezierPath:angle: Advanced Drawing Techniques Creating Gradient Fills 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 115● drawInBezierPath:relativeCenterPosition: These convenience methods are easily identified by the fact that they take either an NSBezierPath or a rectangle as their first parameter. This parameter is used as a clipping region for the gradient when it is drawn. You might use these methods to draw a gradient fill inside an existing shape in your interface. Listing 6-2 shows some code that draws an axial gradient pattern. The NSBezierPath object containing the rounded rectangle shape acts as the clipping region for the gradient when it is drawn. Figure 6-3 (page 117) shows the resulting gradient. Listing 6-2 Clipping an axial gradient to a rounded rectangle - (void)drawRect:(NSRect)rect { NSRect bounds = [self bounds]; NSBezierPath* clipShape = [NSBezierPath bezierPath]; [clipShape appendBezierPathWithRoundedRect:bounds xRadius:40 yRadius:30]; NSGradient* aGradient = [[[NSGradient alloc] initWithColorsAndLocations:[NSColor redColor], (CGFloat)0.0, [NSColor orangeColor], (CGFloat)0.166, [NSColor yellowColor], (CGFloat)0.33, [NSColor greenColor], (CGFloat)0.5, [NSColor blueColor], (CGFloat)0.75, [NSColor purpleColor], (CGFloat)1.0, nil] autorelease]; [aGradient drawInBezierPath:clipShape angle:0.0]; Advanced Drawing Techniques Creating Gradient Fills 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 116} Figure 6-3 Axial gradient drawn inside a Bezier path Using the Primitive Drawing Routines In addition to the high-level convenience methods, the NSGradient class defines two primitive methods for drawing gradients: ● drawFromPoint:toPoint:options: ● drawFromCenter:radius:toCenter:radius:options: These methods give you more flexibility over the gradient parameters, including the ability to extend the gradient colors beyond theirstart and end points. Unlike the high-level routines, these methods do not change the clip region prior to drawing. If you do notset up a custom clip region prior to drawing, the resulting gradient could potentially expand to fill your entire view, depending on the gradient options. Listing 6-3 shows the code for drawing a radial gradient in a view using the primitive drawing routine of NSGradient. The second circle in the gradient is offset from the first one by 60 points in both the horizontal and vertical directions, causing the overall gradient to skew towards the upper-right of the circle. Because the code passes the value 0 for the options parameter, the gradient does not draw beyond the start and end colors and therefore does not fill the entire view. Figure 6-4 (page 118) shows the gradient resulting from this code. Listing 6-3 Drawing a radial gradient using primitive routine - (void)drawRect:(NSRect)rect { NSRect bounds = [self bounds]; NSGradient* aGradient = [[[NSGradient alloc] initWithStartingColor:[NSColor orangeColor] Advanced Drawing Techniques Creating Gradient Fills 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 117endingColor:[NSColor cyanColor]] autorelease]; NSPoint centerPoint = NSMakePoint(NSMidX(bounds), NSMidY(bounds)); NSPoint otherPoint = NSMakePoint(centerPoint.x + 60.0, centerPoint.y + 60.0); CGFloat firstRadius = MIN( ((bounds.size.width/2.0) - 2.0), ((bounds.size.height/2.0) -2.0) ); [aGradient drawFromCenter:centerPoint radius:firstRadius toCenter:otherPoint radius:5.0 options:0]; } Figure 6-4 Gradient created using primitive drawing method Using Quartz Shadings in Cocoa Because the NSGradient class is available only in OS X v10.5 and later, software that runs on earlier versions of OS X must use Quartz or Core Image to draw gradient fills. Quartz supports the creation of both radial and axial gradients in different color spaces using a mathematical computation function you provide. The use of a mathematical function means that the gradients you create using Quartz scale well to any resolution. Core Image, on the other hand, provides filters for creating a fixed-resolution image consisting of a radial, axial, or Gaussian gradient. Because the end result is an image, however, Core Image gradients may be less desirable for PDF and other print-based drawing. To draw a Quartz shading in your Cocoa program, you would do the following from your drawRect: method: 1. Get a CGContextRef using the graphicsPort method of NSGraphicsContext. (You will pass this reference to other Quartz functions.) 2. Create a CGShadingRef using Quartz; see “Gradients” in Quartz 2D Programming Guide . Advanced Drawing Techniques Creating Gradient Fills 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 1183. Configure the current clipping path to the desired shape for your shading; see “Setting the Clipping Region” (page 35). 4. Draw the shading using CGContextDrawShading. For information on using Core Image to create images with gradient fills, see Core Image Programming Guide . Drawing to the Screen If you want to take over the entire screen for your drawing, you can do so from a Cocoa application. Entering full-screen drawing mode is a two-step process: 1. Capture the desired screen (or screens) for drawing. 2. Configure your drawing environment. After capturing the screen, the way you configure your drawing environment depends on whether you are using Cocoa or OpenGL to draw. In OpenGL, you create an NSOpenGLContext object and invoke several of its methodsto enter full-screen mode. In Cocoa, you have to create a window that fillsthe screen and configure that window. Capturing the Screen Cocoa does not provide direct support for capturing and releasing screens. The NSScreen class provides read-only access to information about the available screens. To capture or manipulate a screen, you must use the functions found in Quartz Services. To capture all of the available screens, you can simply call the CGCaptureAllDisplays function. To capture an individual display, you must get the ID of the desired display and call the CGDisplayCapture function to capture it. The following example shows how to use information provided by an NSScreen object to capture the main screen of a system. - (BOOL) captureMainScreen { // Get the ID of the main screen. NSScreen* mainScreen = [NSScreen mainScreen]; NSDictionary* screenInfo = [mainScreen deviceDescription]; NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"]; // Capture the display. Advanced Drawing Techniques Drawing to the Screen 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 119CGDisplayErr err = CGDisplayCapture([screenID longValue]); if (err != CGDisplayNoErr) return NO; return YES; } To release a display you previously captured, use the CGDisplayRelease function. If you captured all of the active displays, you can release them all by calling the CGReleaseAllDisplays function. For more information about capturing and manipulating screens, see Quartz Display Services Reference . Full-Screen Drawing in OpenGL Applications that do full-screen drawing tend to be graphics intensive and thus use OpenGL to improve rendering speed. Creating a full-screen context using OpenGL is easy to do from Cocoa. After capturing the desired displays, create and configure an NSOpenGLContext object and then invoke its setFullScreen and makeCurrentContextmethods. Afterinvoking thesemethods, your application goesimmediately to full-screen mode and you can start drawing content. When requesting a full-screen context in OpenGL, the pixel format for your contextshould include the following attributes: ● NSOpenGLPFAFullScreen ● NSOpenGLPFAScreenMask ● NSOpenGLPFAAccelerated ● NSOpenGLPFANoRecovery (only if your OpenGL graphics context is shared) Listing 6-4 shows the basic steps for capturing all displays and setting up the OpenGL context for full-screen drawing. For information on how to create an NSOpenGLContext object, see “Creating an OpenGL Graphics Context” (page 166). Listing 6-4 Creating an OpenGL full-screen context NSOpenGLContext* CreateScreenContext() { CGDisplayErr err; Advanced Drawing Techniques Drawing to the Screen 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 120err = CGCaptureAllDisplays(); if (err != CGDisplayNoErr) return nil; // Create the context object. NSOpenGLContext* glContext = CreateMyGLContext(); // If the context is bad, release the displays. if (!glContext) { CGReleaseAllDisplays(); return nil; } // Go to full screen mode. [glContext setFullScreen]; // Make this context current so that it receives OpenGL calls. [glContext makeCurrentContext]; return glContext; } Once you go into full-screen mode with your graphics context, your application has full control of the screen. To exit full-screen mode, invoke the clearDrawable method of your OpenGL context and call the CGReleaseAllDisplays function to release the screens back to the system. For detailed sample code showing you how to enter full-screen mode using OpenGL and Cocoa, see the NSOpenGL Fullscreen sample in Sample Code > Graphics & Imaging > OpenGL. Full-Screen Drawing in Cocoa All Cocoa drawing occurs in a window, but for full screen drawing, the window you create is a little different. Instead of a bordered window with a title bar, you need to create a borderless window that spans the entire screen area. Advanced Drawing Techniques Drawing to the Screen 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 121Although you create a full-screen window using Cocoa classes, you still have to use Quartz Services to capture the display and configure the window properly. The capture processis described in “Capturing the Screen” (page 119). Once you capture the screen, the window server puts up a shield window that hides most other content. To make your full-screen window visible, you must adjust its level to sit above this shield. You can get the shield level using the CGShieldingWindowLevel function and pass the returned value to the setLevel: method of your window. Listing 6-5 shows an action method defined in a subclass of NSDocument. The document object uses this method to capture the main display and create the window to fill thatscreen space. The window itself contains a single view (of type MyFullScreenView) for drawing content. (In your own code, you would replace this view with your own custom drawing view.) A reference to the window is stored in the myScreenWindow class instance variable, which is initialized to nil when the class is first instantiated. Listing 6-5 Creating a Cocoa full-screen context - (IBAction)goFullScreen:(id)sender { // Get the screen information. NSScreen* mainScreen = [NSScreen mainScreen]; NSDictionary* screenInfo = [mainScreen deviceDescription]; NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"]; // Capture the screen. CGDirectDisplayID displayID = (CGDirectDisplayID)[screenID longValue]; CGDisplayErr err = CGDisplayCapture(displayID); if (err == CGDisplayNoErr) { // Create the full-screen window if it doesn’t already exist. if (!myScreenWindow) { // Create the full-screen window. NSRect winRect = [mainScreen frame]; myScreenWindow = [[NSWindow alloc] initWithContentRect:winRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO screen:[NSScreen mainScreen]]; Advanced Drawing Techniques Drawing to the Screen 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 122// Establish the window attributes. [myScreenWindow setReleasedWhenClosed:NO]; [myScreenWindow setDisplaysWhenScreenProfileChanges:YES]; [myScreenWindow setDelegate:self]; // Create the custom view for the window. MyFullScreenView* theView = [[MyFullScreenView alloc] initWithFrame:winRect]; [myScreenWindow setContentView:theView]; [theView setNeedsDisplay:YES]; [theView release]; } // Make the screen window the current document window. // Be sure to retain the previous window if you want to use it again. NSWindowController* winController = [[self windowControllers] objectAtIndex:0]; [winController setWindow:myScreenWindow]; // The window has to be above the level of the shield window. int32_t shieldLevel = CGShieldingWindowLevel(); [myScreenWindow setLevel:shieldLevel]; // Show the window. [myScreenWindow makeKeyAndOrderFront:self]; } } To exit full screen mode using Cocoa, simply release the captured display, resize your window so that it does not occupy the entire screen, and set its level back to NSNormalWindowLevel. For more information about the shield window, see Quartz Display Services Reference . Advanced Drawing Techniques Drawing to the Screen 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 123Disabling Screen Updates You can disable and reenable all screen flushes using the NSDisableScreenUpdates and NSEnableScreenUpdates functions. (In OS X v10.4 and later, you can also use the disableScreenUpdatesUntilFlush method of NSWindow.) You can use this technique to synchronize flushes to both a parent and child window. As soon as you reenable screen updates, all windows are flushed simultaneously (or at least close to it). To prevent the system from appearing frozen, the system may automatically reenable screen updates if your application leaves them disabled for a prolonged period of time. If you leave screen updates disabled for more than 1 second, the system automatically reenables them. Using NSTimer for Animated Content By default, Cocoa sends a drawRect: message to your views only when a user action causes something to change. If your view contains animated content, you probably want to update that content at more regular intervals. For both indeterminate-length and finite-length animations, you can do this using timers. Note: For finite-length animations, you can also use an NSAnimation object to control the animation timing. For more information, see “Using Cocoa Animation Objects” (page 125). The NSTimer class provides a mechanism for generating periodic events in your application. When a preset time is reached, the timer object sends a message to your application, giving you the chance to perform any desired actions. For animations, you would use a timer to tell your application that it is time to draw the next frame. There are two steps involved with getting a timer to run. The first step is to create the NSTimer object itself and specify the object to notify, the message to send, the time interval for the notification, and whether the timer repeats. The second step is to install that timer object on the run loop of your thread. The methods scheduledTimerWithTimeInterval:invocation:repeats: and scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: perform both of these steps for you. Other methods of NSTimer create the timer but do not install it on the run loop. For information and examples on how to create and use timers, see Timer Programming Topics. Advanced Drawing Techniques Using NSTimer for Animated Content 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 124Using Cocoa Animation Objects The NSAnimation and NSViewAnimation classes provide sophisticated behavior for animations that occur over a finite length of time. OS X uses animation objects to implement transition animations for user interface elements. You can define custom animation objects to implement animations for your own code. Unlike NSTimer, animation notifications can occur at irregular intervals, allowing you to create animationsthat appear to speed up or slow down. For information about how to use Cocoa animation objects, see Animation Programming Guide for Cocoa . Optimizing Your Drawing Code The following sections provide some basic guidance for improving the overall performance of your drawing code. These are the things that you should definitely be doing in your code. For a more comprehensive list of drawing optimization techniques, see Drawing Performance Guidelines. Draw Minimally Even with modern graphics hardware, drawing is still an expensive operation. The best way to reduce the amount of time spent in your drawing code is to draw only what is needed in the first place. During a view update, the drawRect: method receives a rectangle that specifies the portion of the view that needs to be updated. This rectangle is always limited to the portion of the view that is currently visible and in some cases may be even smaller. Your drawing code should pay attention to this rectangle and avoid drawing content outside of it. Because the rectangle passed to drawRect: might be a union ofseveralsmaller rectangles, an even better approach is to call the view’s getRectsBeingDrawn:count: method and constrain your drawing to the exact list of rectangles returned by that method. Avoid Forcing Synchronous Updates When invalidating portions of your views, you should avoid using the display family of methods to force an immediate update. These methods cause the system to send a drawRect: message to the affected view (and potentially other views in the hierarchy) immediately rather than wait until the next regular update cycle. If there are several areas to update, this may result in a lot of extra work for your drawing code. Instead, you should use the setNeedsDisplay: and setNeedsDisplayInRect: methods to mark areas as needing an update. When you call these methods, the system collects the rectangles you specify and coalesces them into a combined update region, which it then draws during the next update cycle. Advanced Drawing Techniques Using Cocoa Animation Objects 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 125If you are creating animated content, you should also be careful not to trigger visual updates more frequently than the screen refresh rate allows. Updating faster than the refresh rate results in your code drawing frames that are never seen by the user. In addition, updating faster than the refresh rate is not allowed in OS X v10.4 and later. If you try to update the screen faster than the refresh rate, the window server may block the offending thread until the next update cycle. Reuse Your Objects If you have objects that you plan to use more than once, consider caching them for later use. Caching saves time by eliminating the need to recreate objects each time you want to draw them. Of course, caching requires more memory, so be judicious about what you cache. It is faster to recreate an object in memory than page it in from disk. Many objects are cached automatically by Cocoa and do not need to be cached in your own code. For example, Cocoa caches NSColor objects representing commonly used colors as those colors are requested. Minimize State Changes Every time you save the graphics state, you incur a small performance penalty. Whenever you have objects with the same rendering attributes, try to draw them all at the same time. If you save and restore the graphics state for each object, you may waste some CPU cycles. With Cocoa, methods and functions that draw right away usually involve a change in graphics state. For example, when you call the stroke method of NSBezierPath, the object automatically saves the graphics state and appliesthe options associated with that path. While you are building the path, however, the graphics state does not change. Thus, if you want to draw several shapes using the same graphics attributes, it is advantageous to fill a single NSBezierPath with all of the shapes and then draw them all as a group. Note: There is a tradeoff between creating larger, more complex Bezier paths and using individual objects for each shape you want to draw. As path complexity increases, so do the number of calculations required to determine fill characteristics and to perform hit detection—see “Reduce Path Complexity” (page 155). When creating Bezier paths, you need to find an appropriate balance between path complexity and graphics state changes. Advanced Drawing Techniques Optimizing Your Drawing Code 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 126Text rendering is a special type of drawing that is an important part of most applications. Cocoa provides a range of options for rendering text that should satisfy the needs of most developers. The following sections cover these options briefly. For more detailed information, you should see the documents in Reference Library > Cocoa > Text & Fonts. Text Attributes Cocoa provides support for programmatically getting font information using the NSFont class. You can apply fonts as attributes to strings or use them to set the default font in the current context. The Cocoa text system also uses font objects for formatting text. You request NSFont objects from Cocoa using the name and size of the font you want, as shown in the following example. NSFont* font1= [NSFont fontWithName:@"Helvetica" size:9.0]; NSFont* font2 = [NSFont fontWithName:@"Helvetica Bold" size:10.0]; The NSFont class does not provide a programmatic way to modify other text attributes, such as the character spacing and text drawing mode. Cocoa does, however, provide a system Font panel that you can display to the user. From this panel, the user can make changes to the current font attributes. You can also set most text options using the Cocoa text system, which is described in “Advanced Text Drawing” (page 128). Although you usually specify font attributes directly when drawing NSString and NSAttributedString objects, you can also change the font and font size information in the current graphics state. To change these values, you create an NSFont object and invoke its set method. For information about working with fonts and font objects, see Font Handling . For information about how to display the Font panel, see Font Panel Programming Topics. 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 127 TextSimple Text Drawing If you need to draw a small amount of text quickly, the simplest way to do it is using the methods of NSString and NSAttributedString. The Application Kit defines methods on these classes that support drawing the string in the current context. For an NSString object, you can apply basic attributes (such as font, color, and style settings) to the entire string during drawing. For an NSAttributedString object, you can apply multiple sets of attributes to different parts of the string. Prior to OS X v10.4, the NSString and NSAttributedString classes were intended for rendering text occasionally in your program. The performance of these drawing methods was not as good asthe performance you could get by rendering text using the Cocoa text system. Also, the layout for strings is limited to a simple rectangular area in the current view. In OS X v10.4, performance of the string drawing methods improved significantly and is useful in many situations; of course, you should always measure the performance yourself and see if it is adequate for your program. If you need to do more complex text layout, you should still consider using the Cocoa text system. For information on string drawing methods, see NSString Application Kit Additions Reference or NSAttributedString Application Kit Additions Reference in Application Kit Framework Reference . Advanced Text Drawing If your program displays a lot of text or needs to arrange text in complex ways, you should use the Cocoa text system. This system provides advanced text-handling capabilities on top of basic features such as text input, layout, display, editing, copying, and pasting. The system supports multiple fonts and paragraph styles, embedded images, spell checking, nonrectangular text containers, and sophisticated typesetting features, among many other features. Text layout is one of the most expensive drawing-related operations you can do and the Cocoa text system is optimized for the best possible performance. The text system manages a sophisticated set of caches and optimizes the times at which it performs layout to reduce the impact on your program’s drawing cycle. Of course, these optimizations work only if your program reuses its text objects, but doing so is relatively simple. The simplest way to use the Cocoa text system is to place an NSTextView object in one of your windows. A text view object creates and maintainsthe text layout objectsit needsto draw text and respondsto user events to modify the text. If you want to have more control over the text layout and editing behavior, you can tie into the Cocoa text system at several places. The text engine at the heart of the Cocoa text system is highly customizable. You can subclass several text system classes to provide custom layout and typesetting behavior. You can also create your own text-based views to provide features beyond what the default NSTextView offers. Text Simple Text Drawing 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 128For information about the Cocoa text system, you should start by reading Cocoa Text Architecture Guide . That document describes the basic concepts of the text system and introduces you to many of the classes involved in text layout and management. It also provides simple tutorials to get you started and pointers to other text-related documents. Text Advanced Text Drawing 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 129Cocoa provides support for drawing simple or complex geometric shapes using paths. A path is a collection of points used to create primitive shapes such as lines, arcs, and curves. From these primitives, you can create more complex shapes, such as circles, rectangles, polygons, and complex curved shapes, and paint them. Because they are composed of points(as opposed to a rasterized bitmap), paths are lightweight, fast, and scale to different resolutions without losing precision or quality. The following sectionsfocus primarily on the use of the NSBezierPath class, which providesthe main interface for creating and manipulating paths. Cocoa also provides a handful of functions that offer similar behavior for creating and drawing paths but do not require the overhead of creating an object. Those functions are mentioned where appropriate, but for more information,see Foundation Framework Reference and Application Kit Framework Reference . Path Building Blocks Cocoa defines several fundamental data types for manipulating geometric information in the drawing environment. These data types include NSPoint, NSRect, and NSSize. You use these data types to specify lines, rectangles, and width and height information for the shapes you want to draw. Everything from lines and rectangles to circles, arcs, and Bezier curves can be specified using one or more of these data structures. The coordinate values for point, rectangle, and size data types are all specified using floating-point values. Floating-point values allow for much finer precision asthe resolution of the underlying destination device goes up. The NSPoint, NSRect, and NSSize data types have equivalentsin the Quartz environment: CGPoint, CGRect, and CGSize. Because the layout of the Cocoa and Quartz types are identical, you can convert between two types by casting from one type to its counterpart. 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 130 PathsThe NSBezierPath Class The NSBezierPath class provides the behavior for drawing most primitive shapes, and for many complex shapes, it isthe only tool available in Cocoa. An NSBezierPath object encapsulatesthe information associated with a path, including the pointsthat define the path and the attributesthat affect the appearance of the path. The following sections explain how NSBezierPath represents path information and also describe the attributes that affect a path’s appearance. Path Elements An NSBezierPath object uses path elementsto build a path. A path element consists of a primitive command and one or more points. The command tells the path object how to interpret the associated points. When assembled, a set of path elements creates a series of line segments that form the desired shape. The NSBezierPath class handles much of the work of creating and organizing path elementsinitially. Knowing how to manipulate path elements becomes important, however, if you want to make changes to an existing path. If you create a complex path based on user input, you might want to give the user the option of changing that path later. Although you could create a new path object with the changes, it is far simpler to modify the existing path elements. (For information on how to modify path elements, see “Manipulating Individual Path Elements” (page 156).) The NSBezierPath class defines only four basic path element commands, which are listed in Table 8-1. These commands are enough to define all of the possible path shapes. Each command has one or more points that contain information needed to position the path element. Most path elements use the current drawing point as the starting point for drawing. Table 8-1 Path element commands Number Description of points Command Movesthe path object’s current drawing point to the specified point. This path element does not result in any drawing. Using this command in the middle of a path resultsin a disconnected line segment. NSMoveToBezier- 1 PathElement Creates a straight line from the current drawing point to the specified point. Lines and rectangles are specified using this path element. NSLineToBezier- 1 PathElement Paths The NSBezierPath Class 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 131Number Description of points Command Creates a curved line segment from the current point to the specified endpoint using two control pointsto define the curve. The points are stored in the following order: controlPoint1, controlPoint2, endPoint. Ovals, arcs, and Bezier curves all use curve elements to specify their geometry. NSCurveToBezier- 3 PathElement Marks the end of the current subpath at the specified point. (Note that the point specified for the Close Path element is essentially the same as the current point. NSClosePathBezier- 1 PathElement When you add a new shape to a path, NSBezierPath breaks that shape down into one or more component path elements for storage purposes. For example, calling moveToPoint: or lineToPoint: creates a Move To element or Line To element respectively. In the case of more complex shapes, like rectangles and ovals, several line or curve elements may be created. Figure 8-1 shows two shapes and the resulting path elements. For the curved segment, the figure also shows the control points that define the curve. Figure 8-1 Path elements for a complex path Listing 8-1 shows the code that creates the path shown in Figure 8-1. Paths The NSBezierPath Class 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 132Listing 8-1 Creating a complex path NSBezierPath* aPath = [NSBezierPath bezierPath]; [aPath moveToPoint:NSMakePoint(0.0, 0.0)]; [aPath lineToPoint:NSMakePoint(10.0, 10.0)]; [aPath curveToPoint:NSMakePoint(18.0, 21.0) controlPoint1:NSMakePoint(6.0, 2.0) controlPoint2:NSMakePoint(28.0, 10.0)]; [aPath appendBezierPathWithRect:NSMakeRect(2.0, 16.0, 8.0, 5.0)]; Subpaths A subpath is a series of connected line and curve segments within an NSBezierPath object. A single path object may contain multiple subpaths, with each subpath delineated by a Move To or Close Path element. When you set the initial drawing point (typically using the moveToPoint: method), you set the starting point of the first subpath. As you draw, you build the contents of the subpath until you either close the path (using the closePath method) or add another Move To element. At that point, the subpath is considered closed and any new elements are added to a new subpath. Some methods of NSBezierPath automatically create a new subpath for you. For example, creating a rectangle or oval results in the addition of a Move To element, several drawing elements, and a Close Path and Move To element (see Figure 8-1 (page 132) for an example). The Move To element at the end of the list of elements ensures that the current drawing point is left in a known location, which in this case is at the rectangle’s origin point. Subpaths exist to help you distinguish different parts of a path object. For example, subpaths affect the way a path is filled; see “Winding Rules” (page 141). The division of a path into subpaths also affects methods such as bezierPathByReversingPath, which reversesthe subpaths one at a time. In other cases, though,subpaths in an NSBezierPath object share the same drawing attributes. Path Attributes An NSBezierPath object maintains all of the attributes needed to determine the shape of its path. These attributes include the line width, curve flatness, line cap style, line join style, and miter limit of the path. You set these values using the methods of NSBezierPath. Paths The NSBezierPath Class 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 133Path attributes do not take effect until you fill or stroke the path, so if you change an attribute more than once before drawing the path, only the last value is used. The NSBezierPath class maintains both a custom and default version of each attribute. Path objects use custom attribute values if they are set. If no custom attribute value is set for a given path object, the default value is used. The NSBezierPath class does not use path attribute values set using Quartz functions. Note: Path attributes apply to the entire path. If you want to use different attributes for different parts of a path, you must create two separate path objects and apply the appropriate attributes to each. The following sections describe the attributes you can set for a path object and how those attributes affect your rendered paths. Line Width The line width attribute controls the width of the entire path. Line width is measured in points and specified as a floating-point value. The default width for all lines is 1. To change the default line width for all NSBezierPath objects, you use the setDefaultLineWidth: method. To set the line width for the current path object, you use the setLineWidth: method of that path object. To set the default line width for shapes rendered without an NSBezierPath object, you must use the CGContextSetLineWidth function in Quartz. Fractional line widths are rendered as close as possible to the specified width, subject to the limitations of the destination device, the position of the line, and the current anti-aliasing setting. For example, suppose you want to draw a line whose width is 0.2 points. Multiplying this width by 1/72 points per inch yields a line that is 0.0027778 inches wide. On a 90 dpi screen, the smallest possible line would be 1 pixel wide or 0.0111 inches. To ensure your line is not hidden on the screen, Cocoa nominally drawsit at the screen’slarger minimum width (0.0111 inches). In reality, if the line straddles a pixel boundary or anti-aliasing is enabled, the line might affect additional pixels on either side of the path. If the output device were a 600 dpi printer instead, Quartz would be able to render the line closer to its true width of 0.0027778 inches. Listing 8-2 draws a few paths using different techniques. The NSFrameRect function uses the default line width to draw a rectangle, so that value must be set prior to calling the function. Path objects use the default value only if a custom value has not been set. You can even change the line width of a path object and draw again to achieve a different path width, although you would also need to move the path to see the difference. Listing 8-2 Setting the line width of a path // Draw a rectangle using the default line width: 2.0. [NSBezierPath setDefaultLineWidth:2.0]; Paths The NSBezierPath Class 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 134NSFrameRect(NSMakeRect(20.0, 20.0, 10.0, 10.0)); // Set the line width for a single NSBezierPath object. NSBezierPath* thePath = [NSBezierPath bezierPath]; [thePath setLineWidth:1.0]; // Has no effect. [thePath moveToPoint:NSMakePoint(0.0, 0.0)]; [thePath lineToPoint:NSMakePoint(10.0, 0.0)]; [thePath setLineWidth:3.0]; [thePath lineToPoint:NSMakePoint(10.0, 10.0)]; // Because the last value set is 3.0, all lines are drawn with // a width of 3.0, not just the second line. [thePath stroke]; // Changing the width and stroking again draws the same path // using the new line width. [thePath setLineWidth:4.0]; [thePath stroke]; // Changing the default line width has no effect because a custom // value already exists. The path is rendered with a width of 4.0. [thePath setDefaultLineWidth:5.0]; [thePath stroke]; Line Cap Styles The current line cap style determinesthe appearance of the open end points of a path segment. Cocoa supports the line cap styles shown in Figure 8-2. Figure 8-2 Line cap styles Paths The NSBezierPath Class 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 135To set the line cap style for a NSBezierPath object, use the setLineCapStyle: method. The default line cap style is set to NSButtLineCapStyle. To change the default line cap style, use the setDefaultLineCapStyle: method. Listing 8-3 demonstrates both of these methods: Listing 8-3 Setting the line cap style of a path [// Set the default line cap style [NSBezierPath setDefaultLineCapStyle:NSButtLineCapStyle]; // Customize the line cap style for the new object. NSBezierPath* aPath = [NSBezierPath bezierPath]; [aPath moveToPoint:NSMakePoint(0.0, 0.0)]; [aPath lineToPoint:NSMakePoint(10.0, 10.0)]; [aPath setLineCapStyle:NSSquareLineCapStyle]; [aPath stroke]; Line Join Styles The current line join style determines how connected lines in a path are joined at the vertices. Cocoa supports the line join styles shown in Figure 8-3. Figure 8-3 Line join styles To set the line join style for an NSBezierPath object, use the setLineJoinStyle: method. The default line join style is set to NSMiterLineJoinStyle. To change the default line join style, use the setDefaultLineJoinStyle: method. Listing 8-4 demonstrates both of these methods: Paths The NSBezierPath Class 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 136Listing 8-4 Setting the line join style of a path [// Set the default line join style [NSBezierPath setDefaultLineJoinStyle:NSMiterLineJoinStyle]; // Customize the line join style for a new path. NSBezierPath* aPath = [NSBezierPath bezierPath]; [aPath moveToPoint:NSMakePoint(0.0, 0.0)]; [aPath lineToPoint:NSMakePoint(10.0, 10.0)]; [aPath lineToPoint:NSMakePoint(10.0, 0.0)]; [aPath setLineJoinStyle:NSRoundLineJoinStyle]; [aPath stroke]; Line Dash Style The line dash style determines the pattern used to stroke a path. By default, stroked paths appear solid. Using a line-dash pattern, you can specify an alternating group of solid and transparent swatches. When setting a line dash pattern, you specify the width (in points) of each successive solid or transparent swatch. The widths you specify are then repeated over the entire length of the path. Figure 8-4 shows some sample line dash patterns, along with the values used to create each pattern. Figure 8-4 Line dash patterns The NSBezierPath class does not support the concept of a default line dash style. If you want a line dash style, you must apply it to a path explicitly using the setLineDash:count:phase: method as shown in Listing 8-5, which renders the last pattern from the preceding figure. Listing 8-5 Adding a dash style to a path void AddDashStyleToPath(NSBezierPath* thePath) { Paths The NSBezierPath Class 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 137// Set the line dash pattern. float lineDash[6]; lineDash[0] = 40.0; lineDash[1] = 12.0; lineDash[2] = 8.0; lineDash[3] = 12.0; lineDash[4] = 8.0; lineDash[5] = 12.0; [thePath setLineDash:lineDash count:6 phase:0.0]; } Line Flatness The line flatness attribute determinesthe rendering accuracy for curved segments. The flatness value measures the maximum error tolerance (in pixels) to use during rendering. Smaller values result in smoother curves but require more computation time. Larger values result in more jagged curves but are rendered much faster. Line flatness is one parameter you can tweak when you want to render a large number of curves quickly and do not care about accuracy. For example, you might increase this value during a live resize orscrolling operation when accuracy is not as crucial. Regardless, you should always measure performance to make sure such a modification actually saves time. Figure 8-5 shows how changing the default flatness affects curved surfaces. The figure on the left shows a group of curved surfaces rendered with the flatness value set to 0.6 (its default value). The figure on the right shows the same curved surfaces rendered with the flatness value set to 20. The curvature of each surface is lost and now appears to be a set of connected line segments. Figure 8-5 Flatness effects on curves Paths The NSBezierPath Class 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 138To set the flatness for a specific NSBezierPath object, use the setFlatness: method. To set the default flatness value, use setDefaultFlatness:, as shown in Listing 8-6: Listing 8-6 Setting the flatness of a path [- (void) drawRect:(NSRect)rect { if ([self inLiveResize]) { // Adjust the default flatness upward to reduce // the number of required computations. [NSBezierPath setDefaultFlatness:10.0]; // Draw live resize content. } // ... } Miter Limits Miter limits help you avoid spikes that occur when you join two line segments at a sharp angle. If the ratio of the miter length—the diagonal length of the miter—to the line thickness exceeds the miter limit, the corner is drawn using a bevel join instead of a miter join. Paths The NSBezierPath Class 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 139Note: Miter limits apply only to paths rendered using the miter join style. Figure 8-6 shows an example of how different miter limits affect the same path. This path consists of several 10-point wide lines connected by miter joins. In the figure on the left, the miter limit is set to 5. Because the miter lengths exceed the miter limit, the line joins are changed to bevel joins. By increasing the miter limit to 16, as shown in the figure on the right, the miter joins are restored but extend far beyond the point where the two lines meet. Figure 8-6 Miter limit effects To set the miter limits for a specific NSBezierPath object, use the setMiterLimit: method. To set the default miter limit for newly created NSBezierPath objects, use setDefaultMiterLimit:. Listing 8-7 demonstrates both of these methods: Listing 8-7 Setting the miter limit for a path // Increase the default limit [NSBezierPath setDefaultMiterLimit:20.0]; // Customize the limit for a specific path with sharp angles. NSBezierPath* aPath = [NSBezierPath bezierPath]; [aPath moveToPoint:NSMakePoint(0.0, 0.0)]; [aPath lineToPoint:NSMakePoint(8.0, 100.0)]; [aPath lineToPoint:NSMakePoint(16.0, 0.0)]; [aPath setLineWidth:5.0]; [aPath setMiterLimit:5.0]; Paths The NSBezierPath Class 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 140[aPath stroke]; Winding Rules When you fill the area encompassed by a path, NSBezierPath applies the current winding rule to determine which areas of the screen to fill. A winding rule is simply an algorithm that tracks information about each contiguous region that makes up the path's overall fill area. A ray is drawn from a point inside a given region to any point outside the path bounds. The total number of crossed path lines (including implicit lines) and the direction of each path line are then interpreted using the rules in Table 8-2, which determine if the region should be filled. Table 8-2 Winding rules Winding rule Description Count each left-to-right path as +1 and each right-to-left path as -1. If the sum of all crossings is 0, the point is outside the path. If the sum is nonzero, the point isinside the path and the region containing it isfilled. This is the default winding rule. NSNonZeroWindingRule Count the total number of path crossings. If the number of crossings is even, the point is outside the path. If the number of crossings is odd, the point is inside the path and the region containing it should be filled. NSEvenOddWindingRule Fill operations are suitable for use with both open and closed subpaths. A closed subpath is a sequence of drawing calls that ends with a Close Path path element. An open subpath ends with a Move To path element. When you fill a partial subpath, NSBezierPath closes it for you automatically by creating an implicit (non-rendered) line from the first to the last point of the subpath. Paths The NSBezierPath Class 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 141Figure 8-7 shows how the winding rules are applied to a particular path. Subfigure a shows the path rendered using the nonzero rule and subfigure b shows it rendered using the even-odd rule. Subfigures c and d add direction marks and the hidden path line that closes the figure to help you see how the rules are applied to two of the path’s regions. Figure 8-7 Applying winding rules to a path To set the winding rule for an NSBezierPath object, use the setWindingRule: method. The default winding rule is NSNonZeroWindingRule. To change the default winding rule for all NSBezierPath objects, use the setDefaultWindingRule: method. Manipulating Geometric Types The Foundation framework includes numerousfunctionsfor manipulating geometric values and for performing various calculations using those values. In addition to basic equality checks, you can perform more complex operations,such asthe union and intersection of rectangles or the inclusion of a point in a rectangle’s boundaries. Table 8-3 listssome of the more commonly used functions and their behaviors. The function syntax is provided in a shorthand notation, with parameter types omitted to demonstrate the calling convention. For a complete list of available functions, and their full syntax, see the Functions section in Foundation Framework Reference . Paths Manipulating Geometric Types 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 142Table 8-3 Commonly used geometry functions Operation Function Description Returns a properly formatted NSPoint data structure with the specified x and y values. NSPoint NSMakePoint(x, y) Creation Returns a properly formatted NSSize data structure with the specified width and height. NSSize NSMakeSize(w, h) Returns a properly formatted NSRect data structure with the specified origin (x, y) and size (width, height). NSRect NSMakeRect(x, y, w, h) BOOL NSEqualPoints(p1, Returns YES if the two points are the same. p2) Equality Returns YES if the two size types have identical widths and heights. BOOL NSEqualSizes(s1, s2) Returns YES, if the two rectangles have the same origins and the same widths and heights. BOOL NSEqualRects(r1, r2) Returns YES if rectangle 1 completely encloses rectangle 2. BOOL NSContainsRect(r1, r2) Rectangle manipulations Returns a copy of the specified rectangle with its sides moved inward by the specified delta values. Negative delta values move the sides outward. Does not modify the original rectangle. NSRect NSInsetRect(r, dX, dY) NSRect Returns the intersection of the two rectangles. NSIntersectionRect(r1, r2) NSRect NSUnionRect(r1, Returns the union of the two rectangles. r2) Tests whether the point lies within the specified view rectangle. Adjusts the hit-detection algorithm to provide consistent behavior from the user’s perspective. BOOL NSMouseInRect(p, r, flipped) Tests whether the point lies within the specified rectangle. This is a basic mathematical comparison. BOOL NSPointInRect(p, r) Paths Manipulating Geometric Types 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 143Drawing Fundamental Shapes For many types of content, path-based drawing has several advantages over image-based drawing: ● Because paths are specified mathematically, they scale easily to different resolutions. Thus, the same path objects can be used for screen and print-based drawing. ● The geometry information associated with a path requires much less storage space than most image data formats. ● Rendering paths is often faster than compositing a comparable image. It takes less time to transfer path data to the graphics hardware than it takes to transfer the texture data associated with an image. The following sections provide information about the primitive shapes you can draw using paths. You can combine one or more of these shapesto create a more complex path and then stroke or fill the path as described in “Drawing the Shapes in a Path” (page 152). For some shapes, there may be more than one way to add the shape to a path, or there may be alternate waysto draw the shape immediately. Wherever possible, the benefits and disadvantages of each technique are listed to help you decide which technique is most appropriate in specific situations. Adding Points An NSPoint structure by itself represents a location on the screen; it has no weight and cannot be drawn as such. To draw the equivalent of a point on the screen, you would need to create a small rectangle at the desired location, as shown in Listing 8-8. Listing 8-8 Drawing a point void DrawPoint(NSPoint aPoint) { NSRect aRect = NSMakeRect(aPoint.x, aPoint.y, 1.0, 1.0); NSRectFill(aRect); } Of course, a more common use for points is to specify the position of other shapes. Many shapes require you to specify the current point before actually creating the shape. You set the current point using the moveToPoint: or relativeMoveToPoint: methods. Some shapes, like rectangles and ovals, already contain location information and do not require a separate call to moveToPoint:. Paths Drawing Fundamental Shapes 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 144Important: You must specify a starting point before drawing individual line, arc, curve, and glyph paths. If you do not, NSBezierPath raises an exception. Adding Lines and Polygons Cocoa provides a couple of options for adding lines to a path, with each technique offering different tradeoffs between efficiency and correctness. You can draw lines in the following ways: ● Create single horizontal and vertical lines by filling a rectangle using NSRectFill. This technique is less precise but is often a little faster than creating an NSBezierPath object. To create diagonal lines using this technique, you must apply a rotation transform before drawing. This technique is not appropriate for creating connected line segments. ● Use the lineToPoint:, relativeLineToPoint:, or strokeLineFromPoint:toPoint: methods of NSBezierPath to create individual or connected line segments. This technique is fast and is the most precise option for creating lines and complex polygons. ● Use the appendBezierPathWithPoints:count: method to create a series of connected lines quickly. This technique is faster than adding individual lines. Polygons are composed of multiple connected lines and should be created using an NSBezierPath object. The simplest way to create a four-sided nonrectangular shape, like a parallelogram, rhombus, or trapezoid, is using line segments. You could also create these shapes using transforms, but calculating the correct skew factors would require a lot more work. Listing 8-9 shows code to draw a parallelogram using NSBezierPath. The method in this example inscribes the parallelogram inside the specified rectangle. The withShift parameter specifies the horizontal shift applied to the top left and bottom right corners of the rectangular area. Listing 8-9 Using lines to draw a polygon void DrawParallelogramInRect(NSRect rect, float withShift) { NSBezierPath* thePath = [NSBezierPath bezierPath]; [thePath moveToPoint:rect.origin]; [thePath lineToPoint:NSMakePoint(rect.origin.x + withShift, NSMaxY(rect))]; [thePath lineToPoint:NSMakePoint(NSMaxX(rect), NSMaxY(rect))]; [thePath lineToPoint:NSMakePoint(NSMaxX(rect) - withShift, rect.origin.y)]; [thePath closePath]; Paths Drawing Fundamental Shapes 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 145[thePath stroke]; } Adding Rectangles Because rectangles are used frequently, there are several options for drawing them. ● Use the methods of NSBezierPath to create your rectangle. The following methods are reasonably fast and offer the best precision: ● strokeRect: ● fillRect: ● bezierPathWithRect: ● appendBezierPathWithRect: ● Create rectangles using the Cocoa functions described in “Drawing Rectangles” (page 152). These functions draw rectangles faster than, but with less precision than, the methods of NSBezierPath. ● Create a rectangle using individual lines as described in “Adding Lines and Polygons” (page 145). You could use thistechnique to create diagonally oriented rectangles—that is, rectangles whose sides are not parallel to the x and y axes—without using a rotation transform. Listing 8-10 shows a simple function that fills and strokes the same rectangle using two different techniques. The current fill and stroke colors are used when drawing the rectangle, along with the default compositing operation. In both cases, the rectangles are drawn immediately; there is no need to send a separate fill or stroke message. Listing 8-10 Drawing a rectangle void DrawRectangle(NSRect aRect) { NSRectFill(aRect); [NSBezierPath strokeRect:aRect]; } Adding Rounded Rectangles InOS X v10.5 and later, the NSBezierPath classincludesthe following methodsfor creating rounded-rectangles: Paths Drawing Fundamental Shapes 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 146● bezierPathWithRoundedRect:xRadius:yRadius: ● appendBezierPathWithRoundedRect:xRadius:yRadius: These methods create rectangles whose corners are curved according to the specified radius values. The radii describe the width and height of the oval to use at each corner of the rectangle. Figure 8-8 shows how this inscribed oval is used to define the path of the rectangle’s corner segments. Figure 8-8 Inscribing the corner of a rounded rectangle Listing 8-11 shows a code snippet that creates and draws a path with a rounded rectangle. Listing 8-11 Drawing a rounded rectangle void DrawRoundedRect(NSRect rect, CGFloat x, CGFloat y) { NSBezierPath* thePath = [NSBezierPath bezierPath]; [thePath appendBezierPathWithRoundedRect:rect xRadius:x yRadius:y]; [thePath stroke]; } Adding Ovals and Circles To draw ovals and circles, use the following methods of NSBezierPath: ● bezierPathWithOvalInRect: ● appendBezierPathWithOvalInRect: Paths Drawing Fundamental Shapes 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 147Both methods inscribe an oval inside the rectangle you specify. You must then fill or stroke the path object to draw the oval in the current context. The following example creates an oval from the specified rectangle and strokes its path. void DrawOvalInRect(NSRect ovalRect) { NSBezierPath* thePath = [NSBezierPath bezierPath]; [thePath appendBezierPathWithOvalInRect:ovalRect]; [thePath stroke]; } You could also create an oval using arcs, but doing so would duplicate what the preceding methods do internally and would be a little slower. The only reason to add individual arcs is to create a partial (non-closed) oval path. For more information, see “Adding Arcs” (page 148). Adding Arcs To draw arcs, use the following methods of NSBezierPath: ● appendBezierPathWithArcFromPoint:toPoint:radius: ● appendBezierPathWithArcWithCenter:radius:startAngle:endAngle: ● appendBezierPathWithArcWithCenter:radius:startAngle:endAngle:clockwise: The appendBezierPathWithArcFromPoint:toPoint:radius: method creates arcs by inscribing them in an angle formed by the current point and the two points passed to the method. Inscribing a circle in this manner can result in an arc that does not intersect any of the points used to specify it. It can also result in the creation of an unwanted line from the current point to the starting point of the arc. Paths Drawing Fundamental Shapes 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 148Figure 8-9 shows three different arcs and the control points used to create them. For the two arcs created using appendBezierPathWithArcFromPoint:toPoint:radius:, the current point must be set before calling the method. In both examples, the point isset to (30, 30). Because the radius of the second arc isshorter, and the starting point of the arc is not the same as the current point, a line is drawn from the current point to the starting point. Figure 8-9 Creating arcs Listing 8-12 shows the code snippets you would use to create each of the arcs from Figure 8-9. (Although the figure shows the arcs individually, executing the following code would render the arcs on top of each other. ) Listing 8-12 Creating three arcs NSBezierPath* arcPath1 = [NSBezierPath bezierPath]; Paths Drawing Fundamental Shapes 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 149NSBezierPath* arcPath2 = [NSBezierPath bezierPath]; [[NSColor blackColor] setStroke]; // Create the first arc [arcPath1 moveToPoint:NSMakePoint(30,30)]; [arcPath1 appendBezierPathWithArcFromPoint:NSMakePoint(0,30) toPoint:NSMakePoint(0,60) radius:30]; [arcPath1 stroke]; // Create the second arc. [arcPath2 moveToPoint:NSMakePoint(30,30)]; [arcPath2 appendBezierPathWithArcFromPoint:NSMakePoint(30,40) toPoint:NSMakePoint(70,30) radius:20]; [arcPath2 stroke]; // Clear the old arc and do not set an initial point, which prevents a // line being drawn from the current point to the start of the arc. [arcPath2 removeAllPoints]; [arcPath2 appendBezierPathWithArcWithCenter:NSMakePoint(30,30) radius:30 startAngle:45 endAngle:135]; [arcPath2 stroke]; Paths Drawing Fundamental Shapes 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 150Adding Bezier Curves To draw Bezier curves, you must use the curveToPoint:controlPoint1:controlPoint2: method of NSBezierPath. This method supports the creation of a cubic curve from the current point to the destination point you specify when calling the method. The controlPoint1 parameter determinesthe curvature starting from the current point, and controlPoint2 determines the curvature of the destination point, as shown in Figure 8-1 (page 132). Figure 8-10 Cubic Bezier curve Adding Text Because NSBezierPath only supports path-based content, you cannot add text characters directly to a path; instead, you must add glyphs. A glyph is the visual representation of a character (or partial character) in a particular font. For glyphs in an outline font, this visual representation is stored as a set of mathematical paths that can be added to an NSBezierPath object. Note: Using NSBezierPath is not the most efficient way to render text, but can be used in situations where you need the path information associated with the text. To obtain a set of glyphs, you can use the Cocoa text system or the NSFont class. Getting glyphs from the Cocoa text system is usually easier because you can get glyphs for an arbitrary string of characters, whereas using NSFont requires you to know the names of individual glyphs. To get glyphs from the Cocoa text system, you must do the following: 1. Create the text system objects needed to manage text layout. 2. Use the glyphAtIndex: or getGlyphs:range: method of NSLayoutManager to retrieve the desired glyphs. 3. Add the glyphs to your NSBezierPath object using one of the following methods: ● appendBezierPathWithGlyph:inFont: ● appendBezierPathWithGlyphs:count:inFont: Paths Drawing Fundamental Shapes 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 151When added to your NSBezierPath object, glyphs are converted to a series of path elements. These path elements simply specify lines and curves and do not retain any information about the characters themselves. You can manipulate paths containing glyphs just like you would any other path by changing the points of a path element or by modifying the path attributes. Drawing the Shapes in a Path There are two options for drawing the contents of a path: you can stroke the path or fill it. Stroking a path renders an outline of the path’sshape using the currentstroke color and path attributes. Filling the path renders the area encompassed by the path using the current fill color and winding rule. Figure 8-11 shows the same path from Figure 8-1 (page 132) but with the contents filled and a different stroke width applied. Figure 8-11 Stroking and filling a path. Drawing Rectangles Cocoa provides several functions for drawing rectangles to the current context immediately using the default attributes. These functions use Quartz primitives to draw one or more rectangles quickly, but in a way that may be less precise than if you were to use NSBezierPath. For example, these routines do not apply the current join style to the corners of a framed rectangle. Table 8-4 lists some of the more commonly used functions for drawing rectangles along with their behaviors. You can use these functions in places where speed is more important than precision. The syntax for each function is provided in a shorthand notation, with parameter types omitted to demonstrate the calling conventions. For a complete list of available functions, and their full syntax, see Application Kit Functions Reference . Paths Drawing Rectangles 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 152Table 8-4 Rectangle frame and fill functions Function Description void NSEraseRect(aRect) Fills the specified rectangle with white. Drawsthe frame of the rectangle using the current fill color, the default line width, and the NSCompositeCopy compositing operation. void NSFrameRect(aRect) Drawsthe frame of the rectangle using the current fill color, the specified width, and the NSCompositeCopy compositing operation. void NSFrameRectWithWidth(aRect, width) Drawsthe frame of the rectangle using the current fill color, the specified width, and the specified operation. void NSFrameRectWithWidthUsingOperation(aRect, width, op) Fills the rectangle using the current fill color and the NSCompositeCopy compositing operation. void NSRectFill(aRect) Fills the rectangle using the current fill color and specified compositing operation. void NSRectFillUsingOperation(aRect, op) Fillsthe C-style array of rectangles using the current fill color and the NSCompositeCopy compositing operation. void NSRectFillList(rectList, count) Fills the C-style array of rectangles using the corresponding list of colors. Each list must have the same number of entries. void NSRectFillListWithColors(rects, colors, count) Fillsthe C-style array of rectangles using the current fill color and the specified compositing operation. void NSRectFillListUsingOperation(rects, count, op) Fills the C-style array of rectangles using the corresponding list of colors and the specified compositing operation. The list of rectangles and list of colors must contain the same number of items. void NSRectFillListWithColorsUsingOperation(rects, colors, count, op) Paths Drawing Rectangles 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 153Important: You may have noticed that the NSFrameRect, NSFrameRectWithWidth, and NSFrameRectWithWidthUsingOperation functions draw the rectangle using the fill color instead of the stroke color. These methods draw the rectangle’s frame by filling four sub-rectangles, one for each side of the rectangle. This differs from the way NSBezierPath draws rectangles and can sometimes lead to confusion. If your rectangle does not show up the way you expected, check your code to make sure you are setting the drawing color using either the set or setFill method of NSColor. Working with Paths Building a sleek and attractive user interface is hard work and most programs use a combination of images and paths to do it. Paths have the advantage of being lightweight, scalable, and fast. Even so, paths are not appropriate in all situations. The following sections provide some basic tips and guidance on how to use paths effectively in your program. Building Paths Building a path involves creating an NSBezierPath object and adding path elements to it. All paths must start with a Move To element to mark the first point of the path. In some cases, this element is added for you but in others you must add it yourself. For example, methods that create a closed path (such as an oval or rectangle) insert a MoveTo element for you. A single NSBezierPath object may have multiple subpaths. Each subpath is itself a complete path, meaning the subpath may not appear connected to any other subpaths when drawn. Filled subpaths can still interact with each other, however. Overlapping subpaths may cancel each other’s fill effect, resulting in holes in the fill area. All subpaths in an NSBezierPath object share the same drawing attributes. The only way to assign different attributes to different paths is to create different NSBezierPath objects for each. Improving Rendering Performance As you work on your drawing code, you should keep performance in mind. Drawing is a processor intensive activity but there are many waysto reduce the amount of drawing performed by your application. The following sections offersome basic tipsrelated to improving drawing performance with Cocoa applications. For additional drawing-related performance tips, see Drawing Performance Guidelines. Paths Working with Paths 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 154Note: As with any determination of performance, you should measure the speed of your drawing operations before making any changes. If the amount of time spent inside the methods of NSBezierPath becomessignificant,simplifying your paths might offer better performance. Limiting the total amount of drawing you do during an update cycle might also improve performance. Reuse Your Path Objects If you draw the same content repeatedly, consider caching the objects used to draw that content. It is usually more efficient to retain an existing NSBezierPath object than to recreate it during each drawing cycle. For content that might change dynamically, you might also consider maintaining a pool of reusable objects. Correctness Versus Efficiency When writing your drawing code, you should always try to make that code as efficient as possible without sacrificing the quality of the rendered content. If your drawing code seems slow, there are some tradeoffs you can make to improve efficiency that reduce quality only temporarily: ● Use the available update rectanglesto draw only what has changed. Use different NSBezierPath objects for each part of the screen rather than one large object that covers everything. For more information, see “Reduce Path Complexity” (page 155). ● During scrolling, live resizing, or other time-critical operations, consider the following options: ● If your screen contains animated content, pause the animation until the operation is complete. ● Try temporarily increasing the flatness value for curved paths. The default flatness value is set to 0.6, which results in nice smooth curves. Increasing this value above 1.0 may make your curves look more jagged but should improve performance. You may want to try a few different values to determine a good tradeoff between appearance and speed. ● Disable anti-aliasing. For more information, see “Setting the Anti-aliasing Options” (page 37). ● When drawing rectangles, use NSFrameRect and NSRectFill for operations where the highest quality is not required. These functions offer close approximations to what you would get with NSBezierPath but are often a little faster. Reduce Path Complexity If you are drawing a large amount of content, you should do your best to reduce the complexity of the path data you store in a single NSBezierPath object. Path objects with hundreds of path elements require more calculations than those with 10 or 20 elements. Every line or curve segment you add increases the number of calculations required to flatten the path or determine whether a point is inside it. Numerous path crossings also increases the number of required calculations when filling the path. Paths Working with Paths 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 155If the accuracy of rendered paths is not crucial, try using multiple NSBezierPath objects to draw the same content. There is very little visual difference between using one path object or multiple path objects. If your path is already grouped into multiple subpaths, then it becomes easy to put some of those subpaths in other NSBezierPath objects. Using multiple path objects reduces the number of calculations for each subpath and also allows you to limit rendering to only those paths that are in the current update rectangle. Manipulating Individual Path Elements Given an NSBezierPath object with some existing path data, you can retrieve the points associated with that path and modify them individually. An illustration program might do this in response to a mouse event over one of the points in a path. If the mouse event results in that point being dragged to a new location, you can quickly update the path element with the new location and redraw the path. The elementCount method of NSBezierPath returns the total number of path elements for all subpaths of the object. To find out the type of a given path element, use the elementAtIndex: or elementAtIndex:associatedPoints: method. These methods return one of the values listed in Table 8-1 (page 131). Use the elementAtIndex:associatedPoints: method if you also want to retrieve the points associated with an element. If you do not already know the type of the path element, you should pass this method an array capable of holding at least three NSPoint data types. To change the points associated with a path element, use the setAssociatedPoints:atIndex: method. You cannot change the type of a path element, only the points associated with it. When changing the points, NSBezierPath takes only as many points from your point array as are needed. For example, if you specify three points for a Line To path element, only the first point is used. Listing 8-13 shows a method that updates the control point associated with a curve path element on the end of the current path. The pointsthat define the curve are stored in the order controlPoint1, controlPoint2, endPoint. This method replaces the point controlPoint2, which affects the end portion of the curve. Listing 8-13 Changing the control point of a curve path element - (void)replaceLastControlPointWithPoint:(NSPoint)newControl inPath:(NSBezierPath*)thePath { int elemCount = [thePath elementCount]; NSBezierPathElement elemType = [thePath elementAtIndex:(elemCount - 1)]; if (elemType != NSCurveToBezierPathElement) Paths Working with Paths 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 156return; // Get the current points for the curve. NSPoint points[3]; [thePath elementAtIndex:(elemCount - 1) associatedPoints:points]; // Replace the old control point. points[1] = newControl; // Update the points. [thePath setAssociatedPoints:points atIndex:(elemCount - 1)]; } Transforming a Path The coordinate system of an NSBezierPath object always matches the coordinate system of the view in which it is drawn. Thus, given a path whose first point is at (0, 0) in your NSBezierPath object, drawing the path in your view places that point at (0, 0) in the view’s current coordinate system. To draw that path in a different location, you must apply a transform in one of two ways: ● Apply the transform to the view coordinate system and then draw the path. For information on how to apply transforms to a view, see “Creating and Applying a Transform” (page 51). ● Apply the transform to the NSBezierPath object itself using the transformUsingAffineTransform: method and then draw it in an unmodified view. Both techniques cause the path to be drawn at the same location in the view; however, the second technique also has the side effect of permanently modifying the NSBezierPath object. Depending on your content, this may or may not be appropriate. For example, in an illustration program, you might want the user to be able to drag shapes around the view; therefore, you would want to modify the NSBezierPath object to retain the new position of the path. Creating a CGPathRef From an NSBezierPath Object There may be times when it is necessary to convert an NSBezierPath object to a CGPathRef data type so that you can perform path-based operations using Quartz. For example, you might want to draw your path to a Quartz transparency layer or use it to do advanced hit detection. Although you cannot use a NSBezierPath object directly from Quartz, you can use its path elements to build a CGPathRef object. Paths Working with Paths 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 157Listing 8-14 shows you how to create a CGPathRef data type from an NSBezierPath object. The example extends the behavior of the NSBezierPath class using a category. The quartzPath method uses the path elements of the NSBezierPath object to call the appropriate Quartz path creation functions. Although the method creates a mutable CGPathRef object, it returns an immutable copy for drawing. To ensure that the returned path returns correct results during hit detection, this method implicitly closes the last subpath if your code does not do so explicitly. Quartz requires paths to be closed in order to do hit detection on the path’s fill area. Listing 8-14 Creating a CGPathRef from an NSBezierPath @implementation NSBezierPath (BezierPathQuartzUtilities) // This method works only in OS X v10.2 and later. - (CGPathRef)quartzPath { int i, numElements; // Need to begin a path here. CGPathRef immutablePath = NULL; // Then draw the path elements. numElements = [self elementCount]; if (numElements > 0) { CGMutablePathRef path = CGPathCreateMutable(); NSPoint points[3]; BOOL didClosePath = YES; for (i = 0; i < numElements; i++) { switch ([self elementAtIndex:i associatedPoints:points]) { case NSMoveToBezierPathElement: CGPathMoveToPoint(path, NULL, points[0].x, points[0].y); break; case NSLineToBezierPathElement: Paths Working with Paths 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 158CGPathAddLineToPoint(path, NULL, points[0].x, points[0].y); didClosePath = NO; break; case NSCurveToBezierPathElement: CGPathAddCurveToPoint(path, NULL, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y); didClosePath = NO; break; case NSClosePathBezierPathElement: CGPathCloseSubpath(path); didClosePath = YES; break; } } // Be sure the path is closed or Quartz may not do valid hit detection. if (!didClosePath) CGPathCloseSubpath(path); immutablePath = CGPathCreateCopy(path); CGPathRelease(path); } return immutablePath; } @end The code from the preceding example closes only the last open path by default. Depending on your path objects, you might also want to close intermediate subpaths whenever a new Move To element is encountered. If your path objects typically contain only one path, you do not need to do so, however. Paths Working with Paths 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 159Detecting Mouse Hits on a Path If you need to determine whether a mouse event occurred on a path or its fill area, you can use the containsPoint: method of NSBezierPath. This method teststhe point against all closed and open subpaths in the path object. If the point lies on or inside any of the subpaths, the method returns YES. When determining whether a point is inside a subpath, the method uses the nonzero winding rule. If your software runs in OS X v10.4 and later, you can perform more advanced hit detection using the CGContextPathContainsPoint and CGPathContainsPoint functions in Quartz. Using these functions you can determine if a point is on the path itself or if the point is inside the path using either the nonzero or even-odd winding rule. Although you cannot use these functions on an NSBezierPath object directly, you can convert your path object to a CGPathRef data type and then use them. For information on how to convert a path object to a CGPathRef data type, see “Creating a CGPathRef From an NSBezierPath Object” (page 157). Important: Quartz considers a point to be inside a path only if the path is explicitly closed. If you are converting your NSBezierPath objects to Quartz paths for use in hit detection, be sure to close any open subpaths either prior to or during the conversion. If you do not, points lying inside your path may not be correctly identified as such. Listing 8-15 shows an example of how you might perform advanced hit detection on an NSBezierPath object. This example adds a method to the NSBezierPath class using a category. The implementation of the method adds a CGPathRef version of the current path to the current context and calls the CGContextPathContainsPoint function. This function uses the specified mode to analyze the location of the specified point relative to the current path and returns an appropriate value. Modes can include kCGPathFill, kCGPathEOFill, kCGPathStroke, kCGPathFillStroke, or kCGPathEOFillStroke. Listing 8-15 Detecting hits on a path @implementation NSBezierPath (BezierPathQuartzUtilities) // Note, this method works only in OS X v10.4 and later. - (BOOL)pathContainsPoint:(NSPoint)point forMode:(CGPathDrawingMode)mode { CGPathRef path = [self quartzPath]; // Custom method to create a CGPath CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; CGPoint cgPoint; BOOL containsPoint = NO; cgPoint.x = point.x; Paths Working with Paths 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 160cgPoint.y = point.y; // Save the graphics state before doing the hit detection. CGContextSaveGState(cgContext); CGContextAddPath(cgContext, path); containsPoint = CGContextPathContainsPoint(cgContext, cgPoint, mode); CGContextRestoreGState(cgContext); return containsPoint; } @end Paths Working with Paths 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 161Cocoa was designed to integrate well with other technologies in OS X. Many technologies are packaged as Objective-C frameworks, which makesincluding them in Cocoa easy. You are not limited to the use of Objective-C frameworks, though. Cocoa itself uses Quartz internally to implement most drawing routines. You can use Quartz and other C-based technologies,such as OpenGL and QuickTime, from your code with little extra effort. The sections that follow provide information about how to incorporate some of the more important drawing technologies available in OS X. Using Quartz in Your Application Everything you can draw using Cocoa can also be drawn using Quartz. The Cocoa drawing code itself uses Quartz primitives to render content. Cocoa simply adds an object-oriented interface and in some cases does more of the work for you. Cocoa does not provide classes for all Quartz behavior, however. In situations where a feature is not available in Cocoa, you may want to use Quartz directly. For general information about Quartz features and how to use them, see Quartz 2D Programming Guide . Using Quartz Features Because Quartz implements some features that Cocoa does not, there may be times when you need to use Quartz function calls from your Cocoa code. Because Cocoa uses Quartz for most drawing operations, mixing the two technologies is not an issue. Some of the Quartz features that are not supported directly by Cocoa include the following: ● Layers ● Gradients (also called shadings) ● Image data sources ● Blend modes (Cocoa uses compositing modes instead) ● Masking images ● Transparency layers (for grouping content) ● Arbitrary patterns (other than images) 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 162 Incorporating Other Drawing TechnologiesIn each case, you are free to use Quartz functions to take advantage of these features. Some features can produce data types that you can then incorporate back into a Cocoa object. (For example, you can use an image data source to obtain a Quartz image (CGImageRef), which you can then use to create an NSImage object.) In some cases, however, you may need to perform the entire operation using Quartz functions. For information on how to use Quartz features, see Quartz 2D Programming Guide . Graphics Type Conversions When going back and forth between Cocoa and Quartz code,some conversion of data types may be necessary. Table 9-1 shows the Cocoa equivalents of some basic Quartz types. Table 9-1 Simple data-type conversions Cocoa type Quartz type NSRect CGRect NSPoint CGPoint NSSize CGSize Although in each case the structure layout is the same, you cannot pass the Quartz data type directly to a method expecting the Cocoa type. To convert, you must cast from one type to another, as shown in the following example: NSRect cocoaRect = *(NSRect*)&myCGRect; Table 9-2 lists the Cocoa classes that approximate the behavior of specific Quartz data types. In some cases, the Cocoa class wraps an instance of its Quartz counterpart, but that is not always true. In the case of shadows, Quartz provides no direct data type for managing the shadow parameters; you must set shadows attributes in Quartz using several different functions. In the case of layers, there are no Cocoa equivalents. Table 9-2 Equivalent Cocoa and Quartz data types Cocoa type Quartz type NSGraphicsContext CGContextRef NSAffineTransform CGAffineTransform NSColor CGColorRef, CGPatternRef NSFont CGFontRef Incorporating Other Drawing Technologies Using Quartz in Your Application 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 163Cocoa type Quartz type NSGlyph CGGlyph NSImage CGImageRef NSBezierPath CGPathRef NSShadow CGSize, CGColorRef NSGradient (OS X v10.5 and later) CGShadingRef No equivalent CGLayerRef Because Cocoa types often wrap equivalent Quartz types, you should look at the Cocoa reference documentation for information about how to get equivalent Quartz objects, if any. In many cases, Cocoa classes do not offer direct access to their Quartz equivalent and you may need to create the Quartz type based on information in the Cocoa object, such as in the following cases: ● To create a CGPathRef object from an NSBezierPath object, you must redraw the path using Quartz function calls. Use the elementAtIndex:associatedPoints: method of NSBezierPath to retrieve the path’s point information. ● To convert back and forth between CGColorRef and NSColor objects, get the color component values from one object and use those values to create the other object. When creating colors, you may also need to specify the color space for that color. For the most part, Quartz and Cocoa support the same color spaces. If a color uses a custom color space, you can use the available ICC profile data to create the appropriate color space object. ● To create an NSImage object from a Quartz image, you need to create the image object indirectly. For information on how to do this, see “Using a Quartz Image to Create an NSImage” (page 95). ● To create Quartz shadows, you can use the methods of NSShadow to retrieve the color, offset, and blur radius values prior to calling CGContextSetShadow or CGContextSetShadowWithColor. Getting a Quartz Graphics Context Before using any Quartz features, you need to obtain a Quartz graphics context (CGContextRef) for drawing. For view-based drawing, you can get the context by sending a graphicsPort message to the current Cocoa graphics context (NSGraphicsContext). This method returns a pointer that you can cast to a CGContextRef data type and use in subsequent Quartz function calls. Incorporating Other Drawing Technologies Using Quartz in Your Application 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 164Creating a Cocoa Graphics Context Using Quartz In OS X v10.4 and later, if you have an existing Quartz graphics context, you can create a Cocoa graphics context object using the graphicsContextWithGraphicsPort:flipped: class method of NSGraphicsContext. You then use the setCurrentContext: class method to make that context the current context. Modifying the Graphics State When mixing calls to Quartz and Cocoa, remember that many Cocoa classes maintain a local copy of some graphics attributes normally associated with the Quartz graphics context. When such a class is ready to draw its content, it modifiesthe graphicsstate to match itslocalsettings, drawsits content, and restoresthe graphics state to its originalsettings. If you use Quartz to change an attribute that is maintained locally by a Cocoa class, your changes may not be used. If you make changesto the graphicsstate using the NSGraphicsContext class, your changes are immediately conveyed to the Quartz graphics context, and vice versa. If you are not using NSGraphicsContext to set an attribute, you should assume that the attribute is local to the object. For example, the NSBezierPath class prefers local copies of graphics attributes over the default (or global) attributes stored in the current context. Using OpenGL in Your Application OpenGL is an open, cross-platform, three-dimensional (3D) graphics standard with broad industry support. OpenGL eases the task of writing real-time 2D or 3D graphics applications by providing a mature, well-documented graphics processing pipeline that supports the abstraction of current and future hardware accelerators. The sections that follow provide a glimpse into the techniques used to incorporate OpenGL drawing calls into your Cocoa application. For more on OpenGL support in OS X, and for detailed examples of how to integrate OpenGL into your Cocoa application, see OpenGL Programming Guide for Mac . For general information about OpenGL, see Reference Library > Graphics & Imaging > OpenGL. Using NSOpenGLView One way to do OpenGL drawing is to add an OpenGL view (an instance of NSOpenGLView) to your window. An OpenGL view behaves like any other view but also stores a pointer to an OpenGL graphics context object (an instance of NSOpenGLContext). Storing the graphics context in the view eliminates the need for your code to recreate the context during each drawing cycle, which can be expensive. Incorporating Other Drawing Technologies Using OpenGL in Your Application 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 165To use an OpenGL view in your program, you create a subclass of NSOpenGLView and add that view to your window, either programmatically or using Interface Builder. When creating an OpenGL view programmatically, you specify the pixel format object you want to associate with the view. A pixel format object (an instance of NSOpenGLPixelFormat)specifiesthe buffers and other rendering attributes of the OpenGL graphics context. For information on the meaning of different pixel format attributes, see OpenGL Programming Guide for Mac . If you use Interface Builder to add your view to a window, you specify the pixel format information using the inspector for your view. Interface Builder lets you specify some pixel attributes, but not all. To support other attributes, you must replace the view’s pixel format object at runtime using the setPixelFormat: method. Important: If you set the pixel format attributes programmatically, you must do so before getting the OpenGL graphics context using the openGLContext method. The graphics context is created with the current pixel format information and is not recreated if that information changes. Alternatively, you can change the OpenGL graphics context at any time using the setOpenGLContext: method. As with other views, you use your OpenGL view’s drawRect: method to draw the content of your view. When your drawRect: method is invoked, the environment is automatically configured for drawing using the OpenGL graphics context associated with your view. Unlike with other graphics contexts, you do not need to restore the previous OpenGL graphics context when you are done drawing. OpenGL does not maintain a stack of graphics contexts that need to be popped as they are no longer needed. Instead, it simply uses the most recent context that was made current. Creating an OpenGL Graphics Context Before creating an OpenGL graphics context object, you first create a pixel format object (NSOpenGLPixelFormat). The attributes you specify when creating your pixel format object determine the rendering behavior of the graphics context. Once you have a valid pixel format object, you can create and initialize your OpenGL graphics context object. Listing 9-1 attempts to create an OpenGL graphics context that supports full-screen, double-buffered, 32-bit drawing. If the desired renderer is available, it returns the context; otherwise, it returns nil. Listing 9-1 Creating an OpenGL graphics context - (NSOpenGLContext*)getMyContext { // Specify the pixel-format attributes. NSOpenGLPixelFormatAttribute attrs[] = { Incorporating Other Drawing Technologies Using OpenGL in Your Application 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 166NSOpenGLPFAFullScreen, NSOpenGLPFADoubleBuffer, NSOpenGLPFADepthSize, 32, 0 }; // Create the pixel-format object. NSOpenGLContext* myContext = nil; NSOpenGLPixelFormat* pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; // If the pixel format is valid, create the OpenGL context. if (pixFmt != nil) { myContext = [[NSOpenGLContext alloc] initWithFormat:pixFmt shareContext:NO]; } [pixFmt release]; return myContext; } Because the creation of OpenGL graphics contexts depends on the currently available renderers, your code should always verify that the desired objects were created before trying to use them. If creating an object fails, you can always try to create it again using a different set of attributes. Using QuickTime in Your Application QuickTime is Apple's cross-platform multimedia technology designed to help you create and deliver video, sound, animation, graphics, text, interactivity, and music. QuickTime supports dozens of file and compression formats for images, video, and audio, including ISO-compliant MPEG-4 video and AAC audio. You can incorporate QuickTime features into your Cocoa applications in one of two ways. The easiest way is through the QuickTime Kit, which is a full-featured Objective-C based framework for the QuickTime interfaces. If you are already familiar with the C-based QuickTime interfaces, you can use those instead. Incorporating Other Drawing Technologies Using QuickTime in Your Application 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 167Using the QuickTime Kit The QuickTime Kit framework (QTKit.framework) works with QuickTime movies in Cocoa applications in OS X. The QuickTime Kit framework was introduced in OS X v10.4 and was designed as an alternative to and eventual replacement for the existing NSMovie and NSMovieView classes in Cocoa. This new framework provides more extensive coverage of QuickTime functions and data types than had been offered by the Application Kit classes. More importantly, the framework does not require Cocoa programmersto be conversant with Carbon data types such as handles, aliases, file-system specifications, and so on. The QuickTime Kit framework is available primarily in OS X v10.4 and later, but it is also supported in OS X v10.3 with QuickTime 7 or later installed. For information on how to use the QuickTime Kit, see QuickTime Kit Programming Guide . For a reference of the classes in the QuickTime Kit, see QTKit Framework Reference . Using QuickTime C-Based Functions Long before the introduction of the QuickTime Kit framework, QuickTime programs were written using a C-based API. The QuickTime API encompasses thousands of functions and gives you the maximum flexibility in managing QuickTime content. You can use this API in your Cocoa applications like you would any other framework. For an introduction toQuickTime,seeQuickTimeOverview. Forthe completeQuickTime reference,seeQuickTime Framework Reference . Using Quartz Composer Compositions If yoursoftware runsin OS X v10.4 and later, you can use Quartz Composer to render complex graphical content. Quartz Composer usesthe latestOS X graphicstechnologiesto create advanced graphical images and animations quickly and easily. You use the Quartz Composer application to create composition files graphically and then load those compositions into your Cocoa application and run them. Changing the behavior of your Cocoa application is then as simple as updating the composition file. Quartz Composer is especially suited for applications that want to perform complex image manipulations. Through it, you gain easy access to features of Quartz 2D, Core Image, Core Video, OpenGL, QuickTime, MIDI System Services, and Real Simple Syndication (RSS). Your application can render compositions for display or provide the user with controls for manipulating the composition parameters. For a detailed example showing you how to run a composition from your Cocoa application, see the chapter “Using QCRenderer to Play a Composition” in Quartz Composer Programming Guide . Incorporating Other Drawing Technologies Using Quartz Composer Compositions 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 168Choosing the Right Imaging Technology OS X includes several different technologies for manipulating images. Although the NSImage class provide a robust feature set that is sufficient for many developer’s uses, there may be specific times when you need to use other imaging technologies. Table 9-3 lists some of the other imaging technologies available and when you might use each one of them. Table 9-3 Imaging technologies Image Description technology Quartz images are immutable data types that you use to manipulate bitmap data in Quartz. Although NSImage is easier to use and provides automatic support for resolution independence, you might need to create Quartz images if another API you are using expects them. You can create a Quartz image by drawing into a NSBitmapImageRep object or Quartz bitmap context and then extracting a CGImageRef from there. Quartz images are part of the Application Services framework. Quartz Images (CGImageRef) Quartz layers are a mutable alternative to Quartz images. You can draw to layers much like you would draw to an NSImage object. You do so by creating a context, locking focus on that context, drawing, and retrieving an image object from the results. Because they are implemented in video memory, layers can be very efficient to use, especially if you need to draw the same image repeatedly. Quartz layers are available in OS X v10.4 and later as part of the Application Services framework. Quartz Layers (CGLayerRef) The Core Image framework is geared toward processing image data. You would use this technology to apply visual effects or filters to existing bitmap images. Because it is explicitly designed for manipulating bitmap images, you must convert your images to a CIImage object before you do any processing. Core Image is available in OS X v10.4 and later as part of the Quartz Core framework. Core Image (CIImage) The Image I/O framework is geared towards developers who need more direct control over reading and writing image data. You might use this framework to convert imagesfrom one format to another or you might use it to add metadata to an image created by your program. The features of Image I/O are available in OS X v10.4 and later as part of the Application Services framework. Image I/O While not explicitly an imaging technology, the Core Animation framework is a smart and efficient way to render images and other data inside a view. The framework provides a cached backing store that makes it possible to do animations with a minimal amount of redrawing. You might use this technology in place of NSImage or other imaging technologies to create animation effects or other rapidly changing graphics. It offers respectable animation performance without requiring you to use low-level APIs such as OpenGL. The Core Animation framework is available in OS X v10.5 and later as part of the Quartz Core framework. Core Animation Incorporating Other Drawing Technologies Choosing the Right Imaging Technology 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 169This table describes the changes to Cocoa Drawing Guide . Date Notes Added information on supporting offscreen drawing for high resolution displays. 2012-09-19 Added “Drawing Offscreen Images Using a Block-Based Drawing Method to Support High Resolution Displays” (page 89). Updated “Guidelines for Using Images” (page 86). 2012-07-23 Updated links to guidelines on high resolution. 2011-01-18 Corrected reference to application icon image name constant. 2009-10-19 Corrected typos. 2009-01-06 Updated the guidelines associated with resolution independent drawing. Updated advice for creating an NSImage from a CGImageRef. Updated the discussion of screen coordinates. 2008-10-15 2007-10-31 Updated the content for OS X v10.5. Added information about NSGradient and rounded rectangle support. Updated the information about flipped coordinate systems. Fixed bugs in several code examples. Added guidance about which imaging technologies work best for different types of operations. Added the mathematical equations corresponding to the available compositing operations. 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 170 Document Revision HistoryDate Notes Fixed several code examples and added information about how to add a ColorSync profile to a bitmap. 2006-10-03 Changed matrix values to match the values in NSAffineTransformStruct. Fixed example for casting a CGRect to an NSRect. 2006-06-28 2006-04-04 Moved animation object details to "Animation Programming Guide." New document that describes how to draw content from a Cocoa application. 2006-03-08 This document replaces information about Cocoa drawing that was previously published in BasicDrawing , Drawing and Images, TheDrawing Environment, and OpenGL . Document Revision History 2012-09-19 | © 2005, 2012 Apple Inc. All Rights Reserved. 171Apple Inc. © 2005, 2012 Apple Inc. All rights reserved. No part of this publication may be reproduced, stored in a retrievalsystem, or transmitted, in any form or by any means, mechanical, electronic, photocopying, recording, or otherwise, without prior written permission of Apple Inc., with the following exceptions: Any person is hereby authorized to store documentation on a single computer for personal use only and to print copies of documentation for personal use provided that the documentation contains Apple’s copyright notice. No licenses, express or implied, are granted with respect to any of the technology described in this document. Apple retains all intellectual property rights associated with the technology described in this document. This document is intended to assist application developers to develop applications only for Apple-labeled computers. Apple Inc. 1 Infinite Loop Cupertino, CA 95014 408-996-1010 Apple, the Apple logo, Carbon, Cocoa, ColorSync, Mac, Mac OS, Macintosh, Objective-C, OS X, Quartz,QuickDraw,QuickTime, Spaces, and Xcode are trademarks of Apple Inc., registered in the U.S. and other countries. Retina is a trademark of Apple Inc. Adobe, Acrobat, and PostScript are trademarks or registered trademarks of Adobe Systems Incorporated in the U.S. and/or other countries. Helvetica is a registered trademark of Heidelberger Druckmaschinen AG, available from Linotype Library GmbH. OpenGL is a registered trademark of Silicon Graphics, Inc. Even though Apple has reviewed this document, APPLE MAKES NO WARRANTY OR REPRESENTATION, EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS DOCUMENT, ITS QUALITY, ACCURACY, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.ASARESULT, THISDOCUMENT IS PROVIDED “AS IS,” AND YOU, THE READER, ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND ACCURACY. IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,OR CONSEQUENTIAL DAMAGES RESULTING FROM ANY DEFECT OR INACCURACY IN THIS DOCUMENT, even if advised of the possibility of such damages. THE WARRANTY AND REMEDIES SET FORTH ABOVE ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL OR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer, agent, or employee is authorized to make any modification, extension, or addition to this warranty. Some states do not allow the exclusion or limitation of implied warranties or liability for incidental or consequential damages, so the above limitation or exclusion may not apply to you. This warranty gives you specific legal rights, and you may also have other rights which vary from state to state. Cryptographic Services GuideContents About Cryptographic Services 5 At a Glance 5 How to Use This Document 5 Prerequisites 5 See Also 6 Cryptography Concepts In Depth 7 What Is Encryption? 7 Types of Encryption 8 Symmetric Keys 8 Asymmetric Keys 9 Diffie-Hellman Key Exchange 11 Cryptographic Hash Functions 12 Digital Signatures 12 Digital Certificates 14 Encrypting and Hashing Data 19 Encryption Technologies Common to iOS and OS X 19 Keychain Services 19 Cryptographic Message Syntax Services 20 Certificate, Key, and Trust Services 20 Common Crypto 20 Encryption Technologies Specific to OS X 20 Security Transforms 20 CDSA/CSSM 21 OpenSSL 22 Encryption in iOS 22 Managing Keys, Certificates, and Passwords 23 Certificate, Key, and Trust Services 23 Keychain Services 24 To Learn More 24 Generating Random Numbers 25 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 2Generating Random Numbers in OS X 25 Generating Random Numbers in iOS 26 Transmitting Data Securely 27 Using the URL Loading System 28 CFNetwork 28 Secure Transport 29 OpenSSL 29 To Learn More 30 CDSA Overview 31 Apple CDSA Plug-ins 33 AppleCSP Module 33 AppleFileDL Module 33 AppleCSP/DL Module 34 AppleX509CL Module 34 AppleX509TP Module 34 CSSM Services 35 Cryptographic Services 35 Data Store Services 36 Certificate Services 36 Trust Policy Services 36 Authorization Computation Services 36 Document Revision History 37 Glossary 38 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 3 ContentsFigures Cryptography Concepts In Depth 7 Figure 1-1 Asymmetric key encryption 10 Figure 1-2 Creating a digital signature 13 Figure 1-3 Verifying a digital signature 14 Figure 1-4 Anatomy of a digital certificate 15 Figure 1-5 Creating the certificates for the root CA and a secondary CA 16 Figure 1-6 Creating the certificate for an end user and signing a document with it 17 CDSA Overview 31 Figure A-1 OS X implementation of CDSA 32 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 4OS X and iOS provide a number of technologiesthat provide cryptographic services—encryption and decryption, hashing, random number generation, secure network communication, and so on. These technologies can be used to secure data at rest (when stored on your hard drive or other media), secure data in transit, determine the identity of a third party, and build additional security technologies. At a Glance OS X and iOS provide a wide range of cryptographic services, including: ● Encryption and decryption (both general-purpose and special-purpose) ● Key management using keychains ● Cryptographically strong random number generation ● Secure communication (SSL and TLS) ● Secure storage using FileVault and iOS File Protection How to Use This Document “Cryptography Concepts In Depth” (page 7) provides a basic grounding in cryptographic concepts and terminology. These concepts are not specific to OS X or iOS, but are necessary for understanding the rest of the book. “Encrypting Data” (page 19) describes the APIs available in OS X and iOS for general-purpose encryption. Prerequisites Before reading this document, you should be familiar with the conceptsin SecurityOverview and Secure Coding Guide . 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 5 About Cryptographic ServicesSee Also For more information about OS X authentication and authorization (built on top of encryption technologies), read Authentication, Authorization, and Permissions Guide . About Cryptographic Services See Also 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 6The word cryptography (from Greek kryptos, meaning hidden) at its core refers to techniques for making data unreadable to prying eyes. This is not a complete definition, however. In practice, cryptography can includes a range of techniques that can be used for verifying the authenticity of data (detecting modifications), determining the identity of a person or other entity, determining who sent a particular message or created a particular piece of data, sending data securely across a network, locking files securely behind a password or passphrase, and so on. This chapter describes a number of these techniques, beginning with basic encryption, then moving on to other cryptographic constructs built on top of it. Note: This chapter repeats many of the concepts in Security Overview, but with additional detail and depth. It may help to read that document before reading this chapter. What Is Encryption? Encryption is the transformation of data into a form in which it cannot be made sense of without the use of some key. Such transformed data is referred to as ciphertext. Use of a key to reverse this process and return the data to its original (cleartext or plaintext) form is called decryption. Most of the security APIs in OS X and iOS rely to some degree on encryption of text or data. For example, encryption is used in the creation of certificates and digital signatures, in secure storage of secrets in the keychain, and in secure transport of information. Encryption can be anything from a simple process of substituting one character for another—in which case the key is the substitution rule—to a complex mathematical algorithm. For purposes of security, the more difficult it is to decrypt the ciphertext, the better. On the other hand, if the algorithm is too complex, takes too long to do, or requires keys that are too large to store easily, it becomes impractical for use in a personal computer. Therefore,some balance must be reached between strength of the encryption (that is, how difficult it is for someone to discover the algorithm and the key) and ease of use. 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 7 Cryptography Concepts In DepthFor practical purposes, the encryption need only be strong enough to protect the data for the amount of time the data might be useful to a person with malicious intent. For example, if you need to keep your bid on a contract secret only until after the contract has been awarded, an encryption method that can be broken in a few weeks willsuffice. If you are protecting your credit card number, you probably want an encryption method that cannot be broken for many years. Types of Encryption There are two main types of encryption in use in computer security, referred to as symmetric key encryption and asymmetric key encryption . A closely related process to encryption, in which the data is transformed using a key and a mathematical algorithm that cannot be reversed, is called cryptographic hashing. The remainder of thissection discusses encryption keys, key exchange mechanisms(including the Diffie-Hellman key exchange used in some OS X secure transport protocols), and cryptographic hash functions. Symmetric Keys Symmetric key cryptography (also called private key cryptography or secret key cryptography) is the classic use of keysthat most people are familiar with: the same key is used to encrypt and decrypt the data. The classic, and most easily breakable, version of this is the Caesar cipher (named for Julius Caesar), in which each letter in a message is replaced by a letter that is a fixed number of positions away in the alphabet (for example, “a” is replaced by “c”, “b” is replaced by “d”, and so forth). In this case, the key used to encrypt and decrypt the message issimply the number of positionsin the alphabet to shift the letters. Modern symmetric key algorithms are much more sophisticated and much harder to break. However, they share the property of using the same key for encryption and decryption. There are many different algorithms used for symmetric key cryptography, offering anything from minimal to nearly unbreakable security. Some of these algorithms offer strong security, easy implementation in code, and rapid encryption and decryption. Such algorithms are very useful for such purposes as encrypting files stored on a computer to protect them in case an unauthorized individual uses the computer. They are somewhat less useful forsending messagesfrom one computer to another, because both ends of the communication channel must possess the key and must keep it secure. Distribution and secure storage of such keys can be difficult and can open security vulnerabilities. In 1968, the USS Pueblo , a U.S. Navy intelligence ship, was captured by the North Koreans. At the time, every Navy ship carried symmetric keys for a variety of code machines at a variety of security levels. Each key was changed daily. Because there was no way to know how many of these keys had not been destroyed by the Pueblo’s crew and therefore were in the possession of North Korea, the Navy had to assume that all keys being Cryptography Concepts In Depth Types of Encryption 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 8carried by the Pueblo had been compromised. Every ship and shore station in the Pacific theater (that is,several thousand installations, including ships at sea) had to replace all of their keys by physically carrying code books and punched cards to each installation. The Pueblo incident was an extreme case. However, it hassomething in common with the problem of providing secure communication for commerce over the Internet. In both cases, codes are used for sending secure messages, not between two locations, but between a server (the Internetserver or the Navy’s communications center) and a large number of communicants (individual web users or ships and shore stations). The more end users that are involved in the secure communications, the greater the problems of distribution and protection of the secret symmetric keys. Although secure techniques for exchanging or creating symmetric keys can overcome this problem to some extent (for example, Diffie-Hellman key exchange, described later in this chapter), a more practical solution for use in computer communications came about with the invention of practical algorithms for asymmetric key cryptography. Asymmetric Keys In asymmetric key cryptography, different keys are used for encrypting and decrypting a message. The asymmetric key algorithms that are most useful are those in which neither key can be deduced from the other. In that case, one key can be made public while the other is kept secure. There are some distinct advantages to this public-key–private-key arrangement, often referred to as public key cryptography: the necessity of distributing secret keysto large numbers of usersis eliminated, and the algorithm can be used for authentication as well as for cryptography. The first public key algorithm to become widely available was described by Ron Rivest, Adi Shamir, and Len Adleman in 1977, and is known as RSA encryption from their initials. Although other public key algorithms have been created since, RSA is still the most commonly used. The mathematics of the method are beyond the scope of this document, and are available on the Internet and in many books on cryptography. The algorithm is based on mathematical manipulation of two large prime numbers and their product. Its strength is believed to be related to the difficulty of factoring a very large number. With the current and foreseeable speed of modern digital computers, the selection of long-enough prime numbers in the generation of the RSA keys should make this algorithm secure indefinitely. However, this belief has not been proved mathematically, and either a fast factorization algorithm or an entirely different way of breaking RSA encryption might be possible. Also, if practical quantum computers are developed, factoring large numbers will no longer be an intractable problem. Other public key algorithms, based on different mathematics of equivalent complexity to RSA, include ElGamal encryption and elliptic curve encryption. Their use issimilar to RSA encryption (though the mathematics behind them differs), and they will not be discussed further in this document. Cryptography Concepts In Depth Types of Encryption 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 9To see how public key algorithms address the problem of key distribution, assume that Alice wants to receive a secure communication from Bob. The procedure is illustrated in Figure 1-1. Figure 1-1 Asymmetric key encryption The secure message exchange illustrated in Figure 1-1 has the following steps: 1. Alice uses one of the public key algorithms to generate a pair of encryption keys: a private key, which she keeps secret, and a public key. She also prepares a message to send to Bob. 2. Alice sends the public key to Bob, unencrypted. Because her private key cannot be deduced from the public key, doing so does not compromise her private key in any way. 3. Alice can now easily prove her identity to Bob (a process known as authentication ). To do so, she encrypts her message (or any portion of the message) using her private key and sends it to Bob. 4. Bob decrypts the message with Alice’s public key. This proves the message must have come from Alice, as only she has the private key used to encrypt it. Cryptography Concepts In Depth Types of Encryption 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 105. Bob encrypts his message using Alice’s public key and sends it to Alice. The message is secure, because even if it is intercepted, no one but Alice has the private key needed to decrypt it. 6. Alice decrypts the message with her private key. Since encryption and authentication are subjects of great interest in nationalsecurity and protecting corporate secrets, some extremely smart people are engaged both in creating secure systems and in trying to break them. Therefore, itshould come as no surprise that actualsecure communication and authentication procedures are considerably more complex than the one just described. For example, the authentication method of encrypting the message with your private key can be got around by a man-in-the-middle attack, where someone with malicious intent (usually referred to as Eve in books on cryptography) intercepts Alice’s original message and replacesit with their own,so that Bob is using not Alice’s public key, but Eve’s. Eve then intercepts each of Alice’s messages, decrypts it with Alice’s public key, alters it (if she wishes), and reencrypts it with her own private key. When Bob receives the message, he decrypts it with Eve’s public key, thinking that the key came from Alice. Although this is a subject much too broad and technical to be covered in detail in this document, digital certificates and digital signatures can help address these security problems. These techniques are described later in this chapter. Diffie-Hellman Key Exchange The Diffie-Hellman key exchange protocol is a way for two ends of a communication session to generate symmetric private keys through the exchange of public keys. The two sides agree beforehand on the exact algorithm to use and certain parameters, such as the size of the keys. Then each side selects a random number as a private key and uses that number to generate a public key, according to the algorithm. The security of this algorithm dependsin part on it being extremely difficult to derive or guessthe private key from this public key. The two sides exchange public keys and then each generates a session key using their own private key and the other side’s public key. The mathematics of the algorithm is such that, even though neither side knows the other side’s private key, both sides’ session keys are identical. A third party intercepting the public keys but lacking knowledge of either private key cannot generate a session key. Therefore, data encrypted with the session key is secure while in transit. Although Diffie-Hellman key exchange provides strong protection against compromise of intercepted data, it provides no mechanism for ensuring that the entity on the other end of the connection is who you think it is. That is, this protocol is vulnerable to a man-in-the-middle attack. Therefore, it is sometimes used together with some other authentication method to ensure the integrity of the data. Cryptography Concepts In Depth Diffie-Hellman Key Exchange 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 11Diffie-Hellman key exchange is supported by Apple Filing Protocol (AFP) version 3.1 and later and by Apple’s Secure Transport API. Because RSA encryption tends to be slower than symmetric key methods, Diffie-Hellman (and other systems where public keys are used to generate symmetric private keys) can be useful when a lot of encrypted data must be exchanged. Cryptographic Hash Functions A cryptographic hash function takes any amount of data and applies an algorithm that transforms it into a fixed-size output value. For a cryptographic hash function to be useful, it has to be extremely difficult or impossible to reconstruct the original data from the hash value, and it must be extremely unlikely that the same output value could result from any other input data. Sometimes it is more important to verify the integrity of data than to keep it secret. For example, if Alice sent a message to Bob instructing him to shred some records (legally, of course), it would be important to Bob to verify that the list of documents was accurate before proceeding with the shredding. Since the shredding is legal, however, there is no need to encrypt the message, a computationally expensive and time-consuming process. Instead, Alice could compute a hash of the message (called a message digest) and encrypt the digest with her private key. When Bob receives the message, he decrypts the message digest with Alice’s public key (thus verifying that the message is from Alice) and computes his own message digest from the message text. If the two digests match, Bob knows the message has not been corrupted or tampered with. The most common hash function you will use is SHA-1, an algorithm developed and published by the U.S. Government that produces a 160-bit hash value from any data up to 2**64 bits in length. There are also a number of more exotic algorithms such as SHA-2, elliptic-curve-based algorithms, and so on. For compatibility with existing systems and infrastructure, you may occasionally need to use older algorithms such as MD5, but they are not recommended for use in new designs because of known weaknesses. Digital Signatures Digital signatures are a way to ensure the integrity of a message or other data using public key cryptography. Like traditionalsignatures written with ink on paper, they can be used to authenticate the identity of the signer of the data. However, digital signatures go beyond traditional signatures in that they can also ensure that the data itself has not been altered. This is like signing a check in such a way that if someone changes the amount of the sum written on the check, an “Invalid” stamp becomes visible on the face of the check. To create a digital signature, the signer generates a message digest of the data and then uses a private key to encrypt the digest. The signature includes the encrypted digest and information about the signer’s digital certificate. The certificate is used to verify the signature; it includesthe public key needed to decrypt the digest Cryptography Concepts In Depth Cryptographic Hash Functions 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 12and the algorithm used to create the digest. To verify that the signed document has not been altered, the recipient uses the algorithm to create their own message digest and uses the public key to decrypt the digest in the signature. If the two digests are identical, then the message cannot have been altered and must have been sent by the owner of the public key. To ensure that the person who provided the signature is not only the same person who provided the data but is also who they say they are, the certificate is also signed—in this case by the certification authority who issued the certificate. Digital signatures play a key role in code signing. Developers are encouraged to sign their applications. On execution, each application’ssignature is checked for validity. Digitalsignatures are required on all applications for iOS. Read Code Signing Guide for details about how code signing is used by OS X and iOS. Figure 1-2 illustrates the creation of a digital signature. Figure 1-2 Creating a digital signature CA signature CA signature Cryptography Concepts In Depth Digital Signatures 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 13Figure 1-3 illustrates the verification of a digital signature. The recipient gets the signer’s public key from the signer’s certificate and uses that to decrypt the digest. Then, using the algorithm indicated in the certificate, the recipient creates a new digest of the data and compares the new digest to the decrypted copy of the one delivered in the signature. If they match, then the received data must be identical to the original data created by the signer. Figure 1-3 Verifying a digital signature Hash CA signature Digital Certificates A digital certificate is a collection of data used to verify the identity of the holder or sender of the certificate. For example, an X.509 certificate contains such information as: ● Structural information—version,serial number, the message digest algorithm used to create the signature, and so on ● A digital signature from the certificate authority to ensure that the certificate has not been altered and to indicate the identity of the issuer ● Information about the certificate holder—name, email address, company name, the owner’s public key, and so on ● Validity period (the certificate is not valid before or after this period) Cryptography Concepts In Depth Digital Certificates 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 14● Attributes, known as certificate extensions, that contain additional information such as allowable uses for this certificate The careful reader will have noticed that a digital signature includes the certificate of the signer, and that the signer’s certificate, in turn, contains a digital signature that includes another certificate. In general, each certificate is verified through the use of another certificate, creating a chain of trust—a certificate chain that ends with a root certificate. The issuer of a certificate is called a certification authority (CA). The owner of the root certificate is the root certification authority. Figure 1-4 illustrates the anatomy of a digital certificate. Figure 1-4 Anatomy of a digital certificate Cryptography Concepts In Depth Digital Certificates 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 15The root certificate is self-signed, meaning the signature of the root certificate was created by the root certification authority themselves. Figure 1-5 and Figure 1-6 illustrate how a chain of certificates is created and used. Figure 1-5 shows how the root certification authority creates its own certificate and then creates a certificate for a secondary certification authority. Figure 1-5 Creating the certificates for the root CA and a secondary CA Cryptography Concepts In Depth Digital Certificates 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 16Figure 1-6 shows how the secondary certification authority creates a certificate for an end user and how the end user uses it to sign a document. Figure 1-6 Creating the certificate for an end user and signing a document with it In Figure 1-6, the creator of the document has signed the document. The signature indicates the certificate of the document’s creator (labeled User in the figure). The document’s creator signs the document with a private key, and the signing certificate contains the corresponding public key, which can be used to decrypt the message digest to verify the signature (described earlier in “Digital Signatures”). This certificate—together with the private and public keys—was provided by a certification authority (CA). In order to verify the validity of the user’s certificate, the certificate is signed using the certificate of the CA. The certificate of the CA includes the public key needed to decrypt the message digest of the user’s certificate. Continuing the certificate chain, the certificate of the CA is signed using the certificate of the authority who issued that certificate. The chain can go on through any number of intermediate certificates, but in Figure 1-5 Cryptography Concepts In Depth Digital Certificates 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 17the issuer of the CA’s certificate is the root certification authority. Note that the certificate of the root CA, unlike the others, is self-signed—that is, it does not refer to a further certification authority but is signed using the root CA’s own private key. When a CA creates a certificate, it uses its private key to encrypt the certificate’s message digest. The signature of every certificate the CA issues refers to its own signing certificate. The CA’s public key is in this certificate, and the application verifying the signature must extract this key to verify the certificate of the CA. So it continues, on down the certificate chain, to the certificate of the root CA. When a root CA issues a certificate, it, too, signs the certificate. However, this signing certificate was not issued by another CA; the chain stops here. Rather, the root CA issues its own signing certificate, as shown in Figure 1-5. The certificate of the root CA can be verified by creating a digest and comparing it with one widely available. Typically, the root certificate and root CA’s public key are already stored in the application or on the computer that needs to verify the signature. It’s possible to end a certificate chain with a trusted certificate that is not a root certificate. For example, a certificate can be certified as trusted by the user, or can be cross certified—that is, signed with more than one certificate chain. The general term for a certificate trusted to certify other certificates—including root certificates and others—is anchor certificate. Because most anchor certificates are root certificates, the two terms are often used interchangeably. The confidence you can have in a given certificate depends on the confidence you have in the anchor certificate; for example, the trust you have in the certificate authorities and in their proceduresfor ensuring thatsubsequent certificate recipients in the certificate chain are fully authenticated. For this reason, it is always a good idea to examine the certificate that comes with a digital signature, even when the signature appears to be valid. In OS X and iOS, all certificates you receive are stored in your keychain. In OS X, you can use the Keychain Access utility to view them. Certain attributes of a digital certificate (known as certificate extensions) are said to establish a level of trust for a digital certificate. A trust policy is a set of rules that specify the appropriate uses for a certificate that has a specific level of trust. In other words, the level of trust for a certificate is used to answer the question “Should I trust this certificate for this action?” For example, in order to be trusted to verify a digitally signed email message, a certificate must contain an email address that matches the address of the sender of the email. Cryptography Concepts In Depth Digital Certificates 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 18Both symmetric and asymmetric key encryption schemes can be used to encrypt data. Asymmetric encryption is most commonly used for sending data across trust boundaries, such as one person sending another person an encrypted email. It is also often used forsending a symmetric session key across an insecure communication channel so that symmetric encryption can then be used for future communication. Symmetric encryption is most commonly used for data at rest (on your hard drive for example) and as a session key in a number of encrypted networking schemes. OS X and iOS provide a number of different APIs for encryption and decryption. This chapter describes the recommended APIs. Encryption Technologies Common to iOS and OS X OS X and iOS provide a number of encryption technologies. Of these, three APIs are available on both iOS and OS X: ● Keychain Services API—provides secure storage for passwords, keys, and so on ● Cryptographic Message Syntax—provides (non-streaming) symmetric and asymmetric encryption and decryption ● Certificate, Key, and Trust Services—provides cryptographic support services and trust validation The sections that follow describe these technologies. Keychain Services The Keychain Services API is commonly used to store passwords, keys, certificates, and othersecretsin a special encrypted file called a keychain. You should always use the keychain to store passwords and othershort pieces of data (such as cookies) that are used to grant access to secure web sites, as otherwise this data might be compromised if an unauthorized person gains access to a user’s computer, mobile device, or a backup thereof. Although this is mostly used for storing passwords and keys, the keychain can also store small amounts of arbitrary data. The keychain is described further in the next chapter. OS X also includes a utility that allows users to store and read the data in the keychain, called Keychain Access. For more information, see “Keychain Access” in Security Overview. 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 19 Encrypting and Hashing DataCryptographic Message Syntax Services The Cryptographic Message Syntax Services programming interface allows you to encrypt or add a digital signature to S/MIME messages. It is a good API to use when signing or encrypting data for store-and-forward applications, such as email. See Cryptographic Message Syntax Services Reference for details. Certificate, Key, and Trust Services The Certificate, Key, and Trust Services API provides trust validation and support functions for cryptography. These features are described further in “Managing Keys, Certificates, and Passwords” (page 23). In iOS, this API also provides basic encryption capabilities, as described in “Encryption in iOS” (page 22). Common Crypto In OS X v10.5 and later and iOS 5.0 and later, Common Crypto provides low-level C support for encryption and decryption. Common Crypto is not as straightforward as Security Transforms, but provides a wider range of features, including additional hashing schemes, cipher modes, and so on. For more information, see the manual page for CommonCrypto. Encryption Technologies Specific to OS X In addition to Keychain Services and Cryptographic Message Syntax Services, OS X provides four additional APIs for performing encryption: ● Security Transforms API—a Core-Foundation-level API that provides support for signing and verifying, symmetric cryptography, and Base64 encoding and decoding ● Common Crypto—a C-level API that can perform most symmetric encryption and decryption tasks ● CDSA/CSSM—a legacy API thatshould be used only to perform tasks notsupported by the other two APIs, such as asymmetric encryption These APIs are described in the sections that follow. Security Transforms In OS X v10.7 and later, the Security Transforms API provides efficient and easy-to-use support for performing cryptographic tasks. Security transforms are the recommended way to perform symmetric encryption and decryption, asymmetric signing and verifying, and Base64 encoding and decoding in OS X. Encrypting and Hashing Data Encryption Technologies Specific to OS X 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 20Based on the concept of data flow programming, the Security Transforms API lets you construct graphs of transformationsthat feed into one another, transparently using Grand Central Dispatch to schedule the resulting work efficiently across multiple CPUs. As the CFDataRef (or NSData) objects pass through the object graph, callbacks within each individual transform operate on that data, then pass it on to the transform’s output, which may be connected to the input of another transform object, and so on. The transform API also provides a file reader transform (based on CFReadStreamRef or NSInputStream objects) that can be chained to the input of other transforms. Out of the box, the Security Transforms API allows you to read files, perform symmetric encryption and decryption, perform asymmetric signing and verifying, and perform Base64 encoding. The Security Transforms API also provides support for creating custom transforms that perform other operations on data. For example, you might create a transform that byte swaps data prior to encrypting it or a transform that encodes the resulting encrypted data for transport. For more information, read Security Transforms Programming Guide and Security Transforms Reference . CDSA/CSSM Important: CDSA (including CSSM) is deprecated and should not be used for new development. It is not available in iOS. CDSA is an Open Source security architecture adopted as a technical standard by the Open Group. Apple has developed its own Open Source implementation of CDSA, available as part of Darwin at Apple’s Open Source site. This API provides a wide array ofsecurity services, including fine-grained access permissions, authentication of users’ identities, encryption, and secure data storage. Although CDSA has its own standard application programming interface (API), it is complex and does not follow standard Apple programming conventions. For thisreason, the CDSA API is deprecated as of OS X version 10.7 (Lion) and is not available in iOS. Fortunately, OS X and iOS include their own higher-level security APIs that abstract away much of that complexity. Where possible, you should use one of the following instead of using CDSA directly: ● The Security Objective-C API for authentication (in OS X). See “Security Objective-C API” in Security Overview for details. ● The Security Transforms API for symmetric encryption and decryption, asymmetric signing and verifying, and other supported tasks in OS X v10.7 and later. See “Security Transforms” (page 20) for details. ● The Certificate, Key, and Trust Services API for general encryption, key management, and other tasks. See “Encryption in iOS” (page 22) for details. Encrypting and Hashing Data Encryption Technologies Specific to OS X 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 21If these APIs do not meet your needs, you can still use CDSA in OS X, but please file bugs at http://bugreport.apple.com/ to request the additional functionality that you need. For more information, read “CDSA Overview” (page 31). OpenSSL Although OpenSSL is commonly used in the open source community, OpenSSL does not provide a stable API from version to version. For this reason, although OS X provides OpenSSL libraries, the OpenSSL libraries in OS X are deprecated, and OpenSSL has never been provided as part of iOS. Use of the OS X OpenSSL libraries by applications is strongly discouraged. If your application depends on OpenSSL, you should compile OpenSSL yourself and statically link a known version of OpenSSL into your application. This use of OpenSSL is possible on both OS X and iOS. However, unless you are trying to maintain source compatibility with an existing open source project, you should generally use a different API. Common Crypto and Security Transforms are the recommended alternativesfor general encryption. CFNetwork and Secure Transport are the recommended alternatives for secure communications. Encryption in iOS In iOS, in addition to providing support functions for encoding and decoding keys, the Certificate, Key, and Trust Services API also provides basic encryption, decryption, signing, and verifying of blocks of data using the following SecKey functions: SecKeyEncrypt—encrypts a block of data using the specified key. SecKeyDecrypt—decrypts a block of data using the specified key. SecKeyRawSign—signs a block of data using the specified key. SecKeyRawVerify—verifies a signature against a block of data and a specified key. You can find examples of how to use these functions in “Certificate, Key, and Trust Services Tasks for iOS” in Certificate, Key, and Trust Services Programming Guide . For detailed reference content, read Certificate, Key, and Trust Services Reference . Encrypting and Hashing Data Encryption in iOS 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 22The keychain provides storage for passwords, encryption keys, certificates, and other small pieces of data. After an application requests access to a keychain, it can store and retrieve sensitive data, confident that untrusted applications cannot access that data without explicit action by the user. In OS X, the user is prompted for permission when an application needs to access the keychain; if the keychain is locked, the user is asked for a password to unlock it. In iOS, an application can access only its own items in the keychain—the user is never asked for permission or for a password. There are two recommended APIs for accessing the keychain: ● Certificate, Key, and Trust Services ● Keychain Services Certificate, Key, and Trust Services Certificate, Key, and Trust Services is a C API for managing certificates, public and private keys, and trust policies in iOS and OS X. You can use these services in your application to: ● Create certificates and asymmetric keys ● Add certificates and keys to keychains, remove them from keychains, and use keys to encrypt and decrypt data ● Retrieve information about a certificate, such as the private key associated with it, the owner, and so on ● Convert certificates to and from portable representations ● Create and manipulate trust policies and evaluate a specific certificate using a specified set of trust policies ● Add anchor certificates In OS X, functions are also available to retrieve anchor certificates and set user-specified settings for trust policies for a given certificate. In iOS, additional functions are provided to: ● Use a private key to generate a digital signature for a block of data 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 23 Managing Keys, Certificates, and Passwords● Use a public key to verify a signature ● Use a public key to encrypt a block of data ● Use a private key to decrypt a block of data Certificate, Key, and Trust Services operates on certificates that conform to the X.509 ITU standard, uses the keychain for storage and retrieval of certificates and keys, and uses the trust policies provided by Apple. Because certificates are used by SSL and TLS for authentication, the OS X Secure Transport API includes a variety of functions to manage the use of certificates and root certificates in a secure connection. To display the contents of a certificate in an OS X user interface, you can use the SFCertificatePanel and SFCertificateView classes in the Security Objective-C API. In addition, the SFCertificateTrustPanel class displays trust decisions and lets the user edit trust decisions. Keychain Services In OS X and iOS, Keychain Services allows you to create keychains, add, delete, and edit keychain items, and—in OS X only—manage collections of keychains. In most cases, a keychain-aware application does not have to do any keychain management and only has to call a few functions to store or retrieve passwords. By default, backups of iOS data are stored in cleartext, with the exception of passwords and other secrets on the keychain, which remain encrypted in the backup. It is therefore important to use the keychain to store passwords and other data (such as cookies) that are used to accesssecure web sites. Otherwise, this data might be compromised if an unauthorized person gains access to the backup data. To get started using Keychain Services, see Keychain Services Programming Guide and Keychain Services Reference . In OS X, the Keychain Access application provides a user interface to the keychain. See “Keychain Access” in Security Overview for more information about this application. To Learn More For more information about using Keychain Servicesto store and retrieve secrets and certificates, read Keychain Services Programming Guide and Keychain Services Reference . Tor more information about Secure Transport, read “Secure Transport” (page 29). For more information about the certificate user interface API, read “SecurityObjective-C API” in SecurityOverview. Managing Keys, Certificates, and Passwords Keychain Services 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 24Cryptographically secure pseudorandomnumbers are required for a number of encryption algorithms. Because these pseudorandom numbers are generated by a computer algorithm, they are not truly random. However, the algorithm is not discernible from the sequence. The way you generate random numbers depends on whether you are writing code for OS X or iOS. Generating Random Numbers in OS X In OS X, you can get cryptographically secure pseudorandom numbers by reading from /dev/random. Important: Numbers generated by the rand and random APIs are not cryptographically secure. In OS X, given the same initial seed value, both functions reproducibly generate a consistent sequence of values each time you run them, and neither generates an equally distributed set of possible values. For example, if you need a random 64-bit integer value, you could write code like this: FILE *fp = fopen("/dev/random", "r"); if (!fp) { perror("randgetter"); exit(-1); } uint64_t value = 0; int i; for (i=0; i Add Keychain menu item to add them to your list of keychains) to see what they contain and how the certificate chains are constructed. A trust policy (TP) plug-in performs two main functions: it assembles the chain of certificates needed to verify a given certificate, and it determines the level of trust that can be accorded the certificate. The AppleX509TP module performs these functions on X.509 certificates, using trust policies established by Apple. CSSM Services Although the OS X security APIs provide all the capabilities you are ever likely to need for developing secure applications, nearly all the standard CSSM APIs are also available for your use. This section briefly describes the functions provided by each CSSM service. For details, see Common Security: CDSA and CSSM, version 2 (with corrigenda), from the Open Group. Cryptographic Services Cryptographic Services in CSSM provides functions to perform the following tasks: ● Encrypting and decrypting text and data ● Creating and verifying digital signatures ● Creating a cryptographic hash (used for message digests and other purposes) ● Generating symmetric and asymmetric pairs of cryptographic keys ● Generating pseudorandom numbers ● Controlling access to the CSP for creation of keys To see exactly which security protocols and algorithms are supported by Apple’s CSP implementation, see the documentation provided with the Open Source security code, which you can download at Apple’s Open Source site, and the Security Release Notes in the latest Xcode Tools from Apple. CDSA Overview CSSM Services 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 35Data Store Services CSSM Data Store Services provides an API for storing and retrieving data that is independent of the type of storage used. If there is more than one DL module installed, the caller can query Data Store Services to learn the capabilities of each and select which one to use in a particular call. The Apple implementation of Data Store Services supports any standard CDSA DL plug-in module. The AppleFileDL Data Storage Library and AppleCSP/DL Encrypted Data Storage module both implement functions called by Data Store Services. Certificate Services Certificate Services as specified by CDSA performs the following functions: ● Verifies the signatures on certificates and certificate revocation lists ● Creates certificates and certificate revocation lists ● Signs certificates and certificate revocation lists ● Extracts values of fields from certificates and certificate revocation lists ● Searches certificate revocation lists for specified certificates Apple’s implementation of Certificate Services supports all of the CL API functions in the CDSA/CSSM specification. Trust Policy Services The OS X implementation of CSSM Trust Policy Services provides functions to verify certificates, to determine what attributes they contain and therefore the level of trust they can be given, and to construct a chain of related certificates. It does not implement other trust policy functions in the CSSM standard. Documentation for the CSSM trust policy functions supported by Apple’s TP implementation can be found with the Open Source security code, which you can download at Apple’s Open Source site. Authorization Computation Services Apple’s implementation of CSSM does not include the Authorization Computation Services defined in the CDSA standard. Instead, the Authorization Services API calls the Security Server daemon directly (see Figure A-1 (page 32)). CDSA Overview CSSM Services 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 36This table describes the changes to Cryptographic Services Guide . Date Notes 2012-09-19 Updated artwork and made minor editorial fixes. New document that describesthe encryption, decryption,signing, hashing, and other cryptographic technologies in OS X and iOS. 2012-01-09 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 37 Document Revision Historyalgorithm A sequence of actions to accomplish some task. In cryptography, refers to a sequence of actions, usually mathematical calculations, performed on data to encrypt or decrypt it. anchor certificate A digital certificate trusted to be valid, which can then be used to verify other certificates. An anchor certificate can be a root certificate, a cross-certified certificate (that is, a certificate signed with more than one certificate chain), or a locally defined source of trust. asymmetric keys A pair of related but dissimilar keys, one used for encrypting and the other used for decrypting a message or other data. See also public key cryptography. Compare symmetric keys. authentication The process by which a person or other entity (such as a server) proves that it is who (or what) it says it is. Compare authorization; identification. authorization The process by which an entity such as a user or a server gets the right to perform a operation that only specific entities are allowed to perform. (Authorization can also refer to the right itself, as in “Bob has the authorization to run that program.”) Authorization usually involves first authenticating the entity and then determining whether it hasthe appropriate permissions. Compare authentication. BSD Berkeley Software Distribution. BSD is a form of the UNIX operating system and providesthe basis for the OS X file system, including file access permissions. CA See certification authority (CA). CDSA Abbreviation for Common Data Security Architecture. An open software standard for a security infrastructure that provides a wide array of security services, including fine-grained access permissions, authentication of users, encryption, and secure data storage. CDSA has a standard application programming interface, called CSSM. In addition, OS X includes its own security APIs that call the CDSA API for you. See also CDSA plug-in. CDSA plug-in A software module that connects to CDSA through a standard interface and that implements or extends CDSA security services for a particular operating system and hardware environment. certificate See digital certificate. certificate authority See certification authority (CA). certificate chain A sequence of related digital certificates that are used to verify the validity of a digital certificate. Each certificate is digitally signed using the certificate of its certification authority (CA). This creates a chain of certificates ending in an anchor certificate. certificate extension A data field in a digital certificate containing information such as allowable uses for the certificate. Certificate, Key, and Trust Services An API you can use to create, manage, and read certificates; add certificates to a keychain; create encryption keys; and manage trust policies. In iOS, you can also use this API to encrypt, decrypt, and sign data. 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 38 Glossarycertification authority (CA) The issuer of a digital certificate. In order for the digital certificate to be trusted, the certification authority must be a trusted organization that authenticates an applicant before issuing a certificate. CFHTTP An API that you can use to create,serialize, deserialize, and manage HTTP protocol messages, including secure HTTPS messages. This component lets you add authentication information to a message. CFHTTP is a component of CFNetwork and is built on top of CFStream. CFNetwork A high-level API used for creating, sending, and receiving serialized messages over a network. CFNetwork is built on top of Secure Transport, and so can use the Secure Sockets Layer (SSL) and Transport Layer Security (TLS) secure networking protocols. CFStream An API that creates and manages the read and write streams that CFHTTP depends on. CFStream is a component of CFNetwork and is built on top of Secure Transport. You can specify a Secure Sockets Layer (SSL) or Transport Layer Security (TLS) protocol version to encrypt and decrypt the data stream. chain of trust See certificate chain. cipher A scheme for encrypting data. ciphertext Text or other data that has been encrypted. Compare cleartext. cleartext Ordinary, unencrypted data. Compare ciphertext. code signing The addition of a digital signature to an application or block of code. credentials Data that can be used to identify, authenticate, or authorize an entity. For example, a user name and password constitute authentication credentials. A Kerberos ticket, consisting of an encrypted session key and other information, is an example of an identification credential. cryptographic hash function An algorithm that takes any amount of data and transforms it into a fixed-size output value. For a cryptographic hash function to be useful for security, it has to be extremely difficult or impossible to reconstruct the original data from the hash value, and it must be extremely unlikely that the same output value could result from any other input data. See also message digest. cryptographic hashing The process whereby data is transformed using a cryptographic hash function. CSSM Abbreviation for Common Security Services Manager. A public application programming interface for CDSA. CSSM also defines an interface for plug-ins that implement security services for a particular operating system and hardware environment. decryption The transformation of ciphertext back into the original cleartext. Compare encryption. See also asymmetric keys; symmetric keys. Diffie-Hellman key exchange A protocol that provides a way for two ends of a communication session to generate symmetric private keys through the exchange of public keys. digest See message digest. digital certificate A collection of data used to verify the identity of the holder orsender of the certificate. OS X and iOS support the X.509 standard for digital certificates. See also certificate chain. digital ID See digital certificate. Glossary 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 39digital signature A way to ensure the integrity of a message or other data using public key cryptography. To create a digitalsignature, the signer generates a message digest of the data and then uses a private key to encrypt the digest. The signature includes the encrypted digest and identifies the signer. Anyone wanting to verify the signature uses the signer’s digital certificate, which containsthe public key needed to decrypt the digest and specifiesthe algorithm used to create the digest. encryption The transformation of data into a form in which it cannot be made sense of without the use of some key. Such transformed data is referred to as ciphertext. Use of a key to reverse this process and return the data to its original (or cleartext) form is called decryption. hash algorithm See cryptographic hash function. identification The process by which a process verifies that a person or entity is the same one it communicated with previously. Identification is in general faster than authentication and does not require interaction with the user. identity A digital certificate together with an associated private key. key A piece of secret information required to decode an encrypted message. In modern cryptographic methods, it is usually a lengthy integer. keychain A database in OS X and iOS used to store encrypted passwords, private keys, and othersecrets. It is also used to store certificates and other non-secret information that is used in cryptography and authentication. Applications can use the keychain services API (or the legacy keychain manager API) to manipulate data in the keychain. Users can also access keychain data using the Keychain Access utility. Keychain Access An OS X utility that enables users to view and modify the data stored in the keychain. Keychain Services An API forsecurely storing small amounts of data on the keychain. level of trust The confidence you can have in the validity of a certificate, based on the certificates in its certificate chain and on the certificate extensions the certificate contains. The level of trust for a certificate is used together with the trust policy to answer the question “Should I trust this certificate for this action?” man-in-the-middle attack An attack on a communication channel in which the attacker can intercept messages going between two parties without the communicating parties’ knowledge. Typically, the man in the middle substitutes messages and even cryptographic keys to impersonate one party to the other. message digest The result of applying a cryptographic hash function to a message or other data. A cryptographically secure message digest cannot be transformed back into the original message and cannot (or is very unlikely to) be created from a different input. Message digests are used to ensure that a message has not been corrupted or altered. For example, they are used for this purpose in digital signatures. The digital signature includes a digest of the original message, and the recipient prepares their own digest of the received message. If the two digests are identical, then the recipient can be confident that the message has not been altered or corrupted. MIME Acronym for Multipurpose Internet Mail Extensions. A standard for transmitting formatted text, hypertext, graphics, and audio in electronic mail messages over the Internet. PKI See public key infrastructure (PKI). Glossary 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 40plaintext See cleartext. plug-in A code module that uses a standard interface to implement certain features of a program or extend the program. See also CDSA plug-in. private key A cryptographic key that must be kept secret. Whereas a pair of identical private keys can be used as symmetric keys, asymmetric keys consist of one private key and one public key. pseudorandom number A number generated by an algorithm that produces a series of numbers with no discernible pattern. It should be impossible or nearly impossible to deduce the algorithm from such a series. However, unlike a truly random number generator, a pseudorandom number generator always produces the same series if the algorithm is given the same starting value or values. public key A cryptographic key that can be shared or made public without compromising the cryptographic method. See also public key cryptography. public key certificate See digital certificate. public key cryptography A cryptographic method using asymmetric keys in which one key is made public while the other (the private key ) is kept secure. Data encrypted with one key must be decrypted with the other. If the public key is used to encrypt the data, only the holder of the private key can decrypt it; therefore the data is secure from unauthorized use. If the private key is used to encrypt the data, anyone with the public key can decrypt it. Because only the holder of the private key could have encrypted it, however,such data can be used for authentication. See also digital certificate; digital signature. public key infrastructure (PKI) As defined by the X.509 standard, a PKI isthe set of hardware,software, people, policies, and procedures needed to create, manage, store, distribute, and revoke digital certificates that are based on public key cryptography. quantum computer A computer in which the logic gates are based on quantum phenomena such as electron spin rather than mechanical or conventional electronic components. Because of the superposition of quantum states(a consequence of the Heisenberg Uncertainty Principle), a properly designed quantum computer can in principle perform simultaneously certain types of calculations that require a huge number of sequential operations in a classic computer. Consequently, factoring large numbers should be several orders of magnitude faster on a quantum computer than on present-day supercomputers. Because the strength of most modern cryptographic methods depends on the difficulty of making such calculations, a practical quantumcomputer would breakmost cryptographic schemes in common use. Although small proof-of-concept quantum computers have been constructed, no such machine capable of solving practical problems has yet been demonstrated. Randomization Services An iOS API that produces cryptographically secure pseudorandom numbers. root certificate A certificate that can be verified without recourse to another certificate. Rather than being signed by a further certification authority (CA), a root certificate is verified using the widely available public key of the CA that issued the root certificate. Compare anchor certificate. root certification authority The certification authority that owns the root certificate. Glossary 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 41RSA encryption A system of public key cryptography, named for its inventors: Ron Rivest, Adi Shamir, and Leonard Adleman. The RSA algorithm takestwo large prime numbers, findstheir product, and then derives asymmetric keysfrom the prime numbers and their product. Because the public key includes the product, the private key could be derived from the public key if the product could be factored. No easy method for factoring products of large prime numbers is currently known, but it has not been mathematically proven that no such method is possible. Therefore, the discovery of a fast way to factor such numbers, or the development of quantum computers, would break RSA. secret key A cryptographic key that cannot be made public without compromising the security of the cryptographic method. In symmetric key cryptography , the secret key is used both to encrypt and decrypt the data. In asymmetric key cryptography , a (secret) private key is paired with a public key. Whichever one is used to encrypt the data, the other is used to decrypt it. See also public key; public key cryptography. Secure Sockets Layer(SSL) A protocol that provides secure communication over a TCP/IP connection such as the Internet. It uses digital certificates for authentication and digital signatures to ensure message integrity, and can use public key cryptography to ensure data privacy. An SSL service negotiates a secure session between two communicating endpoints. SSL is built into all major browsers and web servers. SSL has been superseded by Transport Layer Security (TLS). secure storage Storage of encrypted data on disk or another medium that persists when the power is turned off. Secure Transport The OS X and iPhone implementation of Secure Sockets Layer (SSL) and Transport Layer Security (TLS), used to create secure connections over TCP/IP connections such as the Internet. On OS X, Secure Transport includes an API that is independent of the underlying transport protocol. The CFNetwork and URL Loading System APIs use the services of Secure Transport. session key A cryptographic key calculated or issued for use only for the duration of a specific communication session. Session keys are used, for example, by the Diffie-Hellman key exchange and Kerberos protocols. S/MIME Acronym for Secure Multipurpose Internet Mail Extensions. A specification that adds digital signature authentication and encryption to electronic mail messages in MIME format. SSL See Secure Sockets Layer (SSL). strength A measure of the amount of effort required to break a security system. For example, the strength of RSA encryption is believed to be related to the difficulty of factoring the product of two large prime numbers. symmetric keys A pair of identical keys used to encrypt and decrypt data. See also private key. Compare asymmetric keys. TLS See Transport Layer Security (TLS). Transport Layer Security (TLS) A protocol that provides secure communication over a TCP/IP connection such as the Internet. It uses digital certificates for authentication and digital signatures to ensure message integrity, and can use public key cryptography to ensure data privacy. A TLS service negotiates a secure session between two communicating endpoints. TLS is built into recent versions of all major browsers and web servers. TLS Glossary 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 42is the successor to SSL. Although the TLS and SSL protocols are not interoperable, Secure Transport can back down to SSL 3.0 if a TLS session cannot be negotiated. trust See level of trust. trust policy A set of rules that specify the appropriate uses for a certificate that has a specific level of trust. For example, the trust policy for a browser might state that if a certificate has an SSL certificate extension, but the certificate has expired, the user should be prompted for permission before a secure session is opened with a web server. URL Loading System An API that you can use to access the contents of http://, https://, and ftp:// URLs. Because https:// websites use Secure Sockets Layer (SSL) or Transport Layer Security (TLS) to protect data transfers, you can use the URL Loading System as a secure transport API. The URL Loading System is layered on top of CFNetwork. X.509 A standard for digital certificates promulgated by the International Telecommunication Union (ITU). The X.509 ITU standard is widely used on the Internet and throughout the information technology industry for designing secure applications based on a public key infrastructure (PKI). Glossary 2012-09-19 | © 2012 Apple Inc. All Rights Reserved. 43Apple Inc. © 2012 Apple Inc. All rights reserved. No part of this publication may be reproduced, stored in a retrievalsystem, or transmitted, in any form or by any means, mechanical, electronic, photocopying, recording, or otherwise, without prior written permission of Apple Inc., with the following exceptions: Any person is hereby authorized to store documentation on a single computer for personal use only and to print copies of documentation for personal use provided that the documentation contains Apple’s copyright notice. No licenses, express or implied, are granted with respect to any of the technology described in this document. Apple retains all intellectual property rights associated with the technology described in this document. This document is intended to assist application developers to develop applications only for Apple-labeled computers. Apple Inc. 1 Infinite Loop Cupertino, CA 95014 408-996-1010 Apple, the Apple logo, Cocoa, FileVault, iPhone, Keychain, Numbers, Objective-C, OS X, and Xcode are trademarks of Apple Inc., registered in the U.S. and other countries. UNIX is a registered trademark of The Open Group. iOS is a trademark or registered trademark of Cisco in the U.S. and other countries and is used under license. Even though Apple has reviewed this document, APPLE MAKES NO WARRANTY OR REPRESENTATION, EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS DOCUMENT, ITS QUALITY, ACCURACY, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.ASARESULT, THISDOCUMENT IS PROVIDED “AS IS,” AND YOU, THE READER, ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND ACCURACY. IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,OR CONSEQUENTIAL DAMAGES RESULTING FROM ANY DEFECT OR INACCURACY IN THIS DOCUMENT, even if advised of the possibility of such damages. THE WARRANTY AND REMEDIES SET FORTH ABOVE ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL OR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer, agent, or employee is authorized to make any modification, extension, or addition to this warranty. Some states do not allow the exclusion or limitation of implied warranties or liability for incidental or consequential damages, so the above limitation or exclusion may not apply to you. This warranty gives you specific legal rights, and you may also have other rights which vary from state to state. Resource Programming GuideContents About Resources 5 At a Glance 5 Nib Files Store the Objects of Your Application’s User Interface 6 String Resources Containing Localizable Text 6 Images, Sounds, and Movies Represent Pre-rendered Content 6 Property Lists and Data Files Separate Data from Code 7 iOS Supports Device-Specific Resources 7 See Also 8 Nib Files 9 Anatomy of a Nib File 9 About Your Interface Objects 10 About the File’s Owner 10 About the First Responder 10 About the Top-Level Objects 11 About Image and Sound Resources 11 Nib File Design Guidelines 11 The Nib Object Life Cycle 12 The Object Loading Process 12 Managing the Lifetimes of Objects from Nib Files 15 Top-level Objects in OS X May Need Special Handling 17 Legacy Patterns 17 Action Methods 20 Built-In Support For Nib Files 21 The Application Loads the Main Nib File 22 Each View Controller Manages its Own Nib File 22 Document and Window Controllers Load Their Associated Nib File 22 Loading Nib Files Programmatically 23 Loading Nib Files Using NSBundle 23 Getting a Nib File’s Top-Level Objects 25 Loading Nib Files Using UINib and NSNib 27 Replacing Proxy Objects at Load Time 28 Accessing the Contents of a Nib File 30 Connecting Menu Items Across Nib Files 30 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 2String Resources 32 Creating Strings Resource Files 33 Choosing Which Strings to Localize 33 About the String-Loading Macros 34 Using the genstrings Tool to Create Strings Files 35 Creating Strings Files Manually 36 Detecting Non-localizable Strings 37 Loading String Resources Into Your Code 37 Using the Core Foundation Framework 38 Using the Foundation Framework 39 Examples of Getting Strings 39 Advanced Strings File Tips 40 Searching for Custom Functions With genstrings 40 Formatting String Resources 41 Using Special Characters in String Resources 41 Debugging Strings Files 42 Image, Sound, and Video Resources 43 Images and Sounds in Nib Files 43 Loading Image Resources 43 Loading Images in Objective-C 44 Loading Images Using Quartz 45 Specifying High-Resolution Images in iOS 46 Data Resource Files 48 Property List Files 48 OS X Data Resource Files 48 Document Revision History 50 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 3 ContentsTables and Listings Nib Files 9 Listing 1-1 Loading a nib file from the current bundle 24 Listing 1-2 Loading a nib in an iPhone application 25 Listing 1-3 Using outlets to get the top-level objects 25 Listing 1-4 Getting the top-level objects from a nib file at runtime 26 Listing 1-5 Loading a nib file using NSNib 28 Listing 1-6 Replacing placeholder objects in a nib file 29 String Resources 32 Table 2-1 Common parameters found in string-loading routines 37 Listing 2-1 A simple strings file 32 Listing 2-2 Strings localized for English 36 Listing 2-3 Strings localized for German 36 Listing 2-4 Strings with formatting characters 41 Image, Sound, and Video Resources 43 Listing 3-1 Loading an image resource 44 Listing 3-2 Using data providers to load image resources 45 Data Resource Files 48 Table 4-1 Other resource types 49 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 4Applied to computer programs, resources are data filesthat accompany a program’s executable code. Resources simplify the code you have to write by moving the creation of complex sets of data or graphical content outside of your code and into more appropriate tools. For example, rather than creating images pixel by pixel using code, it is much more efficient (and practical) to create them in an image editor. To take advantage of a resource, all your code has to do is load it at runtime and use it. In addition to simplifying your code, resources are also an intimate part of the internationalization process for all applications. Rather than hard-coding strings and other user-visible content in your application, you can place that content in external resource files. Localizing your application then becomes a simple process of creating new versions of each resource file for each supported language. The bundle mechanism used in both OS X and iOS provides a way to organize localized resources and to facilitate the loading of resource files that match the user’s preferred language. This document provides information about the types of resources supported in OS X and iOS and how you use those resources in your code. This document does not focus on the resource-creation process. Most resources are created using either third-party applications or the developer tools provided in the /Developer/Applications directory. In addition, although this document refers to the use of resources in applications, the information also applies to other types of bundled executables, including frameworks and plug-ins. Before reading this document, you should be familiar with the organizationalstructure imposed by application bundles. Understanding this structure makes it easier to organize and find the resource files your application uses. For information on the structure of bundles, see Bundle Programming Guide . At a Glance Applications can contain many types of resources but there are several that are supported directly by iOS and OS X. 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 5 About ResourcesNib Files Store the Objects of Your Application’s User Interface Nib files are the quintessential resource type used to create iOS and Mac apps. A nib file is a data archive that essentially contains a set of freeze-dried objects that you want to recreate at runtime. Nib files are used most commonly to store preconfigured windows, views, and other visually oriented objects but they can also store nonvisual objects such as controllers. You create nib files using the Interface Builder application, which provides a graphical assembly area for assembling your objects. When you subsequently load a nib file into your application, the nib-loading code instantiates each object in the file and restores it to the state you specified in Interface Builder. Thus, what you see in Interface Builder is really what you get in your application at runtime. Relevant Chapters: “Nib Files” (page 9) String Resources Containing Localizable Text Text is a prominent part of most user interfaces but also a resource that is most affected by localization changes. Rather than hard-coding text into your code, iOS and OS X support the storage of user-visible text in strings files, which are human-readable text files (in the UTF-16 encoding) containing a set of string resources for an application. (The use of the plural “strings” in is deliberate and due to the .strings filename extension used by files of that type.) Strings files greatly simplify the internationalization and localization process by allowing you to write your code once and then load the appropriately localized text from resource files that can be changed easily. The Core Foundation and Foundation frameworks provide the facilities for loading text from strings files. Applications that use these facilities can also take advantage of tools that come with Xcode to generate and maintain these resource files throughout the development process. Relevant Chapters: “String Resources” (page 32) Images, Sounds, and Movies Represent Pre-rendered Content Images, sound, and movie resources play an important role in iOS and Mac apps. Images are responsible for creating the unique visual style used by each operating system; they also help simplify your drawing code for complex visual elements. Sound and movie files similarly help enhance the overall user experience of your application while simplifying the code needed to create that experience. Both operating systems provide extensive support for loading and presenting these types of resources in your applications. About Resources At a Glance 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 6Relevant Chapters: “Image, Sound, and Video Resources” (page 43) Property Lists and Data Files Separate Data from Code A property list file is a structured file used to store string, number, Boolean, date, and raw data values. Data items in the file are organized using array and dictionary structures with most items associated with a unique key. The system uses property lists to store simple data sets. For example, the Info.plist file found in nearly every application is an example of a property list file. You can also use property list files for simple data storage needs. In addition to property lists, OS X supports some specially structured files for specific uses. For example, AppleScript data and user help are stored using specially formatted data files. You can also create custom data files of your own. Relevant Chapters: “Data Resource Files” (page 48) iOS Supports Device-Specific Resources In iOS 4.0 and later, it is possible to mark individual resource files as usable only on a specific type of device. This capability simplifies the code you have to write for Universal applications. Rather than creating separate code paths to load one version of a resource file for iPhone and a different version of the file for iPad, you can let the bundle-loading routines choose the correct file. All you have to do is name your resource files appropriately. To associate a resource file with a particular device, you add a custom modifier string to its filename. The inclusion of this modifier string yields filenames with the following format: . The string represents the original name of the resource file. It also represents the name you use when accessing the file from your code. Similarly, the string is the standard filename extension used to identify the type of the file. The string is a case-sensitive string that can be one of the following values: ● ~ipad - The resource should be loaded on iPad devices only. ● ~iphone - The resource should be loaded on iPhone or iPod touch devices only. About Resources At a Glance 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 7You can apply device modifiers to any type of resource file. For example, suppose you have an image named MyImage.png. To specify different versions of the image for iPad and iPhone, you would create resource files with the names MyImage~ipad.png and MyImage~iphone.png and include them both in your bundle. To load the image, you would continue to refer to the resource as MyImage.png in your code and let the system choose the appropriate version, as shown here: UIImage* anImage = [UIImage imageNamed:@"MyImage.png"]; On an iPhone or iPod touch device, the system loads the MyImage~iphone.png resource file, while on iPad, it loadsthe MyImage~ipad.png resource file. If a device-specific version of a resource is not found, the system falls back to looking for a resource with the original filename, which in the preceding example would be an image named MyImage.png. See Also The following Apple Developer documents are conceptually related to Resource Programming Guide : ● Bundle Programming Guide describes the bundle structure used by applications to store executable code and resources. ● Internationalization Programming Topics describes the process of preparing an application (and its resources) for translation into other languages. ● Interface Builder User Guide describes the application used to create nib file resources. ● Property List Programming Guide describes the facilities in place for loading property-list resource files into a Cocoa application. ● Property List Programming TopicsforCore Foundation describesthe facilitiesinplace forloadingproperty-list resource files into a C-based application. About Resources See Also 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 8Nib files play an important role in the creation of applications in OS X and iOS. With nib files, you create and manipulate your user interfaces graphically, using Xcode, instead of programmatically. Because you can see the results of your changesinstantly, you can experiment with different layouts and configurations very quickly. You can also change many aspects of your user interface later without rewriting any code. For applications built using the AppKit or UIKit frameworks, nib files take on an extra significance. Both of these frameworks support the use of nib files both for laying out windows, views, and controls and for integrating those items with the application’s event handling code. Xcode works in conjunction with these frameworks to help you connect the controls of your user interface to the objects in your project that respond to those controls. This integration significantly reduces the amount of setup that is required after a nib file is loaded and also makes it easy to change the relationships between your code and user interface later. Note: Although you can create an Objective-C application without using nib files, doing so is very rare and not recommended. Depending on your application, avoiding nib files might require you to replace large amounts of framework behavior to achieve the same results you would get using a nib file. Anatomy of a Nib File A nib file describes the visual elements of your application’s user interface, including windows, views, controls, and many others. It can also describe non-visual elements,such asthe objectsin your application that manage your windows and views. Most importantly, a nib file describes these objects exactly as they were configured in Xcode. At runtime, these descriptions are used to recreate the objects and their configuration inside your application. When you load a nib file at runtime, you get an exact replica of the objectsthat were in your Xcode document. The nib-loading code instantiates the objects, configures them, and reestablishes any inter-object connections that you created in your nib file. The following sections describe how nib files used with the AppKit and UIKit frameworks are organized, the types of objects found in them, and how you use those objects effectively. 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 9 Nib FilesAbout Your Interface Objects Interface objects are what you add to an nib file to implement your user interface. When a nib is loaded at runtime, the interface objects are the objects actually instantiated by the nib-loading code. Most new nib files have at least one interface object by default, typically a window or menu resource, and you add more interface objects to a nib file as part of your interface design. This is the most common type of object in a nib file and is typically why you create nib files in the first place. Besides representing visual objects, such as windows, views, controls, and menus, interface objects can also represent non-visual objects. In nearly all cases, the non-visual objects you add to a nib file are extra controller objects that your application uses to manage the visual objects. Although you could create these objects in your application, it is often more convenient to add them to a nib file and configure them there. Xcode provides a generic object that you use specifically when adding controllers and other non-visual objects to a nib file. It also provides the controller objects that are typically used to manage Cocoa bindings. About the File’s Owner One of the most important objects in a nib file is the File’s Owner object. Unlike interface objects, the File’s Owner object is a placeholder object that is not created when the nib file is loaded. Instead, you create this object in your code and pass it to the nib-loading code. The reason this object is so important is that it is the main link between your application code and the contents of the nib file. More specifically, it is the controller object that is responsible for the contents of the nib file. In Xcode, you can create connections between the File’s Owner and the other interface objects in your nib file. When you load the nib file, the nib-loading code recreates these connections using the replacement object you specify. This allows your object to reference objects in the nib file and receive messages from the interface objects automatically. About the First Responder In a nib file, the First Responder is a placeholder object that represents the first object in your application’s dynamically determined responder chain. Because the responder chain of an application cannot be determined at design time, the First Responder placeholder acts as a stand-in target for any action messages that need to be directed at the application’sresponder chain. Menu items commonly target the First Responder placeholder. For example, the Minimize menu item in the Window menu hides the frontmost window in an application, not just a specific window, and the Copy menu item should copy the current selection, not just the selection of a single control or view. Other objects in your application can target the First Responder as well. When you load a nib file into memory, there is nothing you have to do to manage or replace the First Responder placeholder object. The AppKit and UIKit frameworks automatically set and maintain the first responder based on the application’s current configuration. Nib Files Anatomy of a Nib File 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 10For more information about the responder chain and how it is used to dispatch events in AppKit–based applications,see “Event Architecture” inCocoa Event Handling Guide . For information about the responder chains and handling actions in iPhone applications, see Event Handling Guide for iOS . About the Top-Level Objects When your program loads a nib file, Cocoa recreates the entire graph of objects you created in Xcode. This object graph includes all of the windows, views, controls, cells, menus, and custom objects found in the nib file. The top-level objects are the subset of these objects that do not have a parent object. The top-level objects typically include only the windows, menubars, and custom controller objects that you add to the nib file. (Objects such as File’s Owner, First Responder, and Application are placeholder objects and not considered top-level objects.) Typically, you use outlets in the File’s Owner object to store references to the top-level objects of a nib file. If you do not use outlets, however, you can retrieve the top-level objects from the nib-loading routines directly. You should always keep a pointer to these objects somewhere because your application is responsible for releasing them when it is done using them. For more information about the nib object behavior at load time, see “Managing the Lifetimes of Objects from Nib Files” (page 15). About Image and Sound Resources In Xcode, you can refer to external image and sound resources from within the contents of your nib files. Some controls and views are able to display images or play sounds as part of their default configuration. The Xcode library provides access to the image and sound resources of your Xcode projects so that you can link your nib files to these resources. The nib file does not store these resources directly. Instead, it stores the name of the resource file so that the nib-loading code can find it later. When you load a nib file that contains references to image or sound resources, the nib-loading code reads the actual image or sound file into memory and and caches it. In OS X, image and sound resources are stored in named caches so that you can access them later if needed. In iOS, only image resources are stored in named caches. To access images, you use the imageNamed: method of NSImage or UIImage, depending on your platform. To access cached sounds in OS X, use the soundNamed: method of NSSound. Nib File Design Guidelines When creating your nib files, it is important to think carefully about how you intend to use the objects in that file. A very simple application might be able to store all of its user interface components in a single nib file, but for most applications, it is better to distribute components across multiple nib files. Creating smaller nib files lets you load only those portions of your interface that you need immediately. They also make it easier to debug any problems you might encounter, since there are fewer places to look for problems. Nib Files Nib File Design Guidelines 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 11When creating your nib files, try to keep the following guidelines in mind: ● Design your nib files with lazy loading in mind. Plan on loading nib files that contain only those objects you need right away. ● In the main nib file for an OS X application, considerstoring only the application menu bar and an optional application delegate object in the nib file. Avoid including any windows or user-interface elements that will not be used until after the application has launched. Instead, place those resources in separate nib files and load them as needed after launch. ● Store repeated user-interface components (such as document windows) in separate nib files. ● For a window or menu that is used only occasionally,store it in a separate nib file. By storing it in a separate nib file, you load the resource into memory only if it is actually used. ● Make the File’s Owner the single point-of-contact for anything outside of the nib file; see “Accessing the Contents of a Nib File” (page 30). The Nib Object Life Cycle When a nib file is loaded into memory, the nib-loading code takes several steps to ensure the objects in the nib file are created and initialized properly. Understanding these steps can help you write better controller code to manage your user interfaces. The Object Loading Process When you use the methods of NSNib or NSBundle to load and instantiate the objectsin a nib file, the underlying nib-loading code does the following: 1. It loads the contents of the nib file and any referenced resource files into memory: ● The raw data for the entire nib object graph is loaded into memory but is not unarchived. ● Any custom image resources associated with the nib file are loaded and added to the Cocoa image cache; see “About Image and Sound Resources” (page 11). ● Any custom sound resources associated with the nib file are loaded and added to the Cocoa sound cache; see “About Image and Sound Resources” (page 11). 2. It unarchives the nib object graph data and instantiates the objects. How it initializes each new object depends on the type of the object and how it was encoded in the archive. The nib-loading code uses the following rules (in order) to determine which initialization method to use. a. By default, objects receive an initWithCoder: message. Nib Files The Nib Object Life Cycle 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 12In OS X, the list of standard objects includes the views, cells, menus, and view controllers that are provided by the system and available in the default Xcode library. It also includes any third-party objects that were added to the library using a custom plug-in. Even if you change the class of such an object, Xcode encodes the standard object into the nib file and then tells the archiver to swap in your custom class when the object is unarchived. In iOS, any object that conforms to the NSCoding protocol is initialized using the initWithCoder: method. This includes all subclasses of UIView and UIViewController whether they are part of the default Xcode library or custom classes you define. b. Custom views in OS X receive an initWithFrame: message. Custom views are subclasses of NSView for which Xcode does not have an available implementation. Typically, these are viewsthat you define in your application and use to provide custom visual content. Custom views do not include standard system views(like NSSlider) that are part of the default library or part of an integrated third-party plug-in. When it encounters a custom view, Xcode encodes a special NSCustomView object into your nib file. The custom view object includesthe information it needsto build the real view subclass you specified. At load time, the NSCustomView object sends an alloc and initWithFrame: message to the real view class and then swaps the resulting view object in for itself. The net effect is that the real view object handles subsequent interactions during the nib-loading process. Custom views in iOS do not use the initWithFrame: method for initialization. c. Custom objects other than those described in the preceding steps receive an init message. 3. It reestablishes all connections(actions, outlets, and bindings) between objectsin the nib file. Thisincludes connections to File’s Owner and other placeholder objects. The approach for establishing connections differs depending on the platform: ● Outlet connections ● In OS X, the nib-loading code tries to reconnect outlets using the object’s own methods first. For each outlet, Cocoa looks for a method of the form setOutletName: and calls it if such a method is present. If it cannot find such a method, Cocoa searchesthe object for an instance variable with the corresponding outlet name and tries to set the value directly. If the instance variable cannot be found, no connection is created. In OS X v10.5 and later, setting an outlet also generates a key-value observing (KVO) notification for any registered observers. These notifications may occur before all inter-object connections are reestablished and definitely occur before any awakeFromNib methods of the objects have been called. Prior to v10.5, these notifications are not generated. For more information about KVO notifications, see Key-Value Observing Programming Guide . Nib Files The Nib Object Life Cycle 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 13● In iOS, the nib-loading code uses the setValue:forKey: method to reconnect each outlet. That method similarly looks for an appropriate accessor method and falls back on other means when that fails. For more information about how this method sets values, see its description in NSKeyValueCoding Protocol Reference . Setting an outlet in iOS also generates a KVO notification for any registered observers. These notifications may occur before all inter-object connections are reestablished and definitely occur before any awakeFromNib methods of the objects have been called. For more information about KVO notifications, see Key-Value Observing Programming Guide . ● Action connections ● In OS X, the nib-loading code uses the source object’s setTarget: and setAction: methods to establish the connection to the target object. If the target object does not respond to the action method, no connection is created. If the target object is nil, the action is handled by the responder chain. ● In iOS, the nib-loading code uses the addTarget:action:forControlEvents: method of the UIControl object to configure the action. If the target is nil, the action is handled by the responder chain. ● Bindings ● In OS X, Cocoa usesthe bind:toObject:withKeyPath:options: method of the source object to create the connection between it and its target object. ● Bindings are not supported in iOS. 4. It sends an awakeFromNib message to the appropriate objects in the nib file that define the matching selector: ● In OS X, this message is sent to any interface objects that define the method. It is also sent to the File’s Owner and any placeholder objects that define it as well. ● In iOS, this message is sent only to the interface objects that were instantiated by the nib-loading code. It is not sent to File’s Owner, First Responder, or any other placeholder objects. 5. It displays any windows whose “Visible at launch time” attribute was enabled in the nib file. The order in which the nib-loading code calls the awakeFromNib methods of objects is not guaranteed. In OS X, Cocoa tries to call the awakeFromNib method of File’s Owner last but does not guarantee that behavior. If you need to configure the objects in your nib file further at load time, the most appropriate time to do so is after your nib-loading call returns. At that point, all of the objects are created, initialized, and ready for use. Nib Files The Nib Object Life Cycle 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 14Managing the Lifetimes of Objects from Nib Files Each time you ask the NSBundle or NSNib class to load a nib file, the underlying code creates a new copy of the objects in that file and returns them to you. (The nib-loading code does not recycle nib file objects from a previous load attempt.) You need to ensure that you maintain the new object graph as long as necessary, and disown it when you are finished with it. You typically need strong references to top-level objects to ensure that they are not deallocated; you don’t need strong references to objects lower down in the graph because they’re owned by their parents, and you should minimize the risk of creating strong reference cycles. From a practical perspective, in iOS and OS X outlets should be defined as declared properties. Outlets should generally be weak, except for those from File’s Owner to top-level objects in a nib file (or, in iOS, a storyboard scene) which should be strong. Outlets that you create should therefore typically be weak, because: ● Outlets that you create to subviews of a view controller’s view or a window controller’s window, for example, are arbitrary references between objects that do not imply ownership. ● The strong outlets are frequently specified by framework classes (for example, UIViewController’s view outlet, or NSWindowController’s window outlet). @property (weak) IBOutlet MyView *viewContainerSubview; @property (strong) IBOutlet MyOtherClass *topLevelObject; Note: InOS X, not all classessupport weak references; these are NSATSTypesetter, NSColorSpace, NSFont, NSFontManager, NSFontPanel, NSImage, NSMenuView, NSParagraphStyle, NSSimpleHorizontalTypesetter, NSTableCellView, NSTextView, NSViewController, NSWindow, and NSWindowController, and all classes in the AV Foundation framework. In cases where you cannot therefore specify weak, you should instead use assign: @property (assign) IBOutlet NSTextView *textView; Outlets may be considered private to the defining class; if you prefer, you can hide the property declarations a class extension. For example: // MyClass.h @interface MyClass : MySuperclass @end Nib Files Managing the Lifetimes of Objects from Nib Files 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 15// MyClass.m @interface MyClass () @property (weak) IBOutlet MyView *viewContainerSubview; @property (strong) IBOutlet MyOtherClass *topLevelObject; @end These patterns extend to references from a container view to its subviews where you have to consider the internal consistency of your object graph. For example, in the case of a table view cell, outlets to specific subviews should again typically be weak. If a table view contains an image view and a text view, then these remain valid so long as they are subviews of the table view cell itself. Outlets should be changed to strong when the outlet should be considered to own the referenced object: ● Asindicated previously, thisis often the case with File’s Owner—top level objectsin a nib file are frequently considered to be owned by the File’s Owner. ● You may in some situations need an object from a nib file to exist outside of its original container. For example, you might have an outlet for a view that can be temporarily removed from itsinitial view hierarchy and must therefore be maintained independently. Classes that you expect to be subclassed (in particular abstract classes) expose outlets publicly so that they can be used appropriately by subclasses (e.g. UIViewController’s view outlet). Outlets might also be exposed where there is an expectation that consumers of the class will need to interact with the property; for example a table view cell might expose subviews. In thislatter case, it may be appropriate to expose a read-only public outlet that is redefined privately as read-write, for example: // MyClass.h @interface MyClass : UITableViewCell @property (weak, readonly) MyType *outletName; @end // MyClass.m @interface MyClass () @property (weak, readwrite) IBOutlet MyType *outletName; @end Nib Files Managing the Lifetimes of Objects from Nib Files 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 16Top-level Objects in OS X May Need Special Handling For historical reasons, in OS X the top-level objects in a nib file are created with an additional reference count. The Application Kit offers a couple of features that help to ensure that nib objects are properly released: ● NSWindow objects (including panels) have an isReleasedWhenClosed attribute, which if set to YES instructs the window to release itself (and consequently all dependent objects in its view hierarchy) when it is closed. In the nib file, you set this option through the “Release when closed” check box in the Attributes pane of the Xcode inspector. ● If the File’s Owner of a nib file is an NSWindowController object (the default in document nibs in document-based applications—recall that NSDocument manages an instance of NSWindowController) or an NSViewController object, it automatically disposes of the windows it manages. If the File’s Owner is not an instance of NSWindowController or NSViewController, then you need to decrement the reference count of the top level objects yourself. With manual reference counting, it was possible to achieve this by sending top-level objects a release message. You cannot do this with ARC. Instead, you cast references to top-level objects to a Core Foundation type and use CFRelease. (If you don’t want to have outlets to all top-level objects, you can use the instantiateNibWithOwner:topLevelObjects: method of the NSNib class to get an array of a nib file’s top-level objects.) Legacy Patterns Prior to ARC, the rules for managing nib objects are different from those described above. How you manage the objects depends on the platform and on the memory model in use. Whichever platform you develop for, you should define outlets using the Objective-C declared properties feature. The general form of the declaration should be: @property (attributes) IBOutlet UserInterfaceElementClass *anOutlet; Because the behavior of outlets depends on the platform, the actual declaration differs: ● For iOS, you should use: @property (nonatomic, retain) IBOutlet UserInterfaceElementClass *anOutlet; ● For OS X, you should use: @property (assign) IBOutlet UserInterfaceElementClass *anOutlet; Nib Files Managing the Lifetimes of Objects from Nib Files 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 17You should then either synthesize the corresponding accessor methods, or implement them according to the declaration, and (in iOS) release the corresponding variable in dealloc. This pattern also works if you use the modern runtime and synthesize the instance variables, so it remains consistent across all situations. Managing Nib Objects in iOS Top-Level Objects Objects in the nib file are created with a retain count of 1 and then autoreleased. As it rebuilds the object hierarchy, UIKit reestablishes connections between the objects using setValue:forKey:, which uses the available setter method or retains the object by default if no setter method is available. This means that (assuming you follow the pattern shown above) any object for which you have an outlet remains valid. If there are any top-level objects you do not store in outlets, however, you must retain either the array returned by the loadNibNamed:owner:options: method or the objects inside the array to prevent those objects from being released prematurely. Memory Warnings When a view controller receives a memory warning (didReceiveMemoryWarning), it should relinquish ownership of resources that are currently not needed and that can be recreated later if required. One such resource is the view controller's view itself. If it does not have a superview, the view is disposed of (in its implementation of didReceiveMemoryWarning, UIViewController invokes [self setView:nil]). Because outlets to elements within the nib file are typically retained, however, even though the main view is disposed of, absent any further action the outlets are not disposed of. This is not in and of itself a problem—if and when the main view is reloaded, they will simply be replaced—but it does mean that the beneficial effect of the didReceiveMemoryWarning is reduced. To ensure that you properly relinquish ownership of outlets, in your custom view controller class you can implement viewDidUnload to invoke your accessor methods to set outlets to nil. - (void)viewDidUnload { self.anOutlet = nil; [super viewDidUnload]; } Nib Files Managing the Lifetimes of Objects from Nib Files 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 18Managing Nib Objects in OS X In OS X, the File’s Owner of a nib file is by default responsible for releasing the top-level objects in a nib file as well as any non-object resources created by the objects in the nib. The release of the root object of an object graph sets in motion the release of all dependent objects. The File’s Owner of an application’s main nib file (which containsthe application menu and possibly other items) isthe global application object NSApp. However, when a Cocoa application terminates, top level objects in the main nib do not automatically get dealloc messages just because NSApp is being deallocated. In other words, even in the main nib file, you have to manage the memory of top-level objects. The Application Kit offers a couple of features that help to ensure that nib objects are properly released: ● NSWindow objects (including panels) have an isReleasedWhenClosed attribute, which if set to YES instructs the window to release itself (and consequently all dependent objects in its view hierarchy) when it is closed. In the nib file, you set this option through the “Release when closed” check box in the Attributes pane of the inspector. ● If the File’s Owner of a nib file is an NSWindowController object (the default in document nibs in document-based applications—recall that NSDocument manages an instance of NSWindowController), it automatically disposes of the windows it manages. So in general, you are responsible for releasing top-level objects in a nib file. But in practice, if your nib file’s owner is an instance of NSWindowController it releases the top-level object for you. If one of your objects loads the nib itself (and the owner is not an instance of NSWindowController), you can define outlets to each top-level object so that at the appropriate time you can release them using those references. If you don’t wantto have outletsto alltop-level objects, you can use the instantiateNibWithOwner:topLevelObjects: method of the NSNib class to get an array of a nib file’s top-level objects. The issue of responsibility for nib object disposal becomes clearer when you consider the various kinds of applications. Most Cocoa applications are of two kinds: single window applications and document-based applications. In both cases, memory management of nib objects is automatically handled for you to some degree. With single-window applications, objects in the main nib file persist through the runtime life of the application and are released when the application terminates; however, dealloc is not guaranteed to be automatically invoked on objects from the main nib file when an application terminates. In document-based applications each document window is managed by an NSWindowController object which handles memory management for a document nib file. Some applications may have a more complex arrangement of nib files and top-level objects. For example, an application could have multiple nib files with multiple window controllers, loadable panels, and inspectors. But in most of these cases, if you use NSWindowController objects to manage windows and panels or if you set the “released when closed” window attribute, memory management is largely taken care of. If you decide against using window controllers and do not want to set the “release when closed” attribute, you should Nib Files Managing the Lifetimes of Objects from Nib Files 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 19explicitly free your nib file’s windows and other top-level objects when the window is closed. Also, if your application uses an inspector panel, (after being lazily loaded) the panel should typically persist throughout the lifetime of the application—there is no need to dispose of the inspector and its resources. Action Methods Broadly speaking, action methods(see Target-Action in OS X or Target-Action in iOS) are methodsthat are typically invoked by another object in a nib file. Action methods use type qualifier IBAction, which is used in place of the void return type, to flag the declared method as an action so that Xcode is aware of it. @interface MyClass - (IBAction)myActionMethod:(id)sender; @end You may choose to regard action methods as being private to your class and thus not declare them in the public @interface. (Because Xcode parses implementation files, there is no need to declare them in the header.) // MyClass.h @interface MyClass @end // MyClass.m @implementation MyClass - (IBAction)myActionMethod:(id)sender { // Implementation. } @end You should typically not invoke an action method programmatically. If your class needs to perform the work associated with the action method, then you should factor the implementation into a different method that is then invoked by the action method. // MyClass.h Nib Files Action Methods 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 20@interface MyClass @end // MyClass.m @interface MyClass (PrivateMethods) - (void)doSomething; - (void)doWorkThatRequiresMeToDoSomething; @end @implementation MyClass - (IBAction)myActionMethod:(id)sender { [self doSomething]; } - (void)doSomething { // Implementation. } - (void)doWorkThatRequiresMeToDoSomething { // Pre-processing. [self doSomething]; // Post-processing. } @end Built-In Support For Nib Files The AppKit and UIKit frameworks both provide a certain amount of automated behavior for loading and managing nib files in an application. Both frameworks provide infrastructure for loading an application’s main nib file. In addition, the AppKit framework providessupport for loading other nib filesthrough the NSDocument and NSWindowController classes. The following sections describe the built-in support for nib files, how you can take advantage of it, and ways to modify that support in your own applications. Nib Files Built-In Support For Nib Files 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 21The Application Loads the Main Nib File Most of the Xcode project templates for applications come preconfigured with a main nib file already in place. All you have to do is modify this default nib file in the nib file and build your application. At launch time, the application’s default configuration data tells the application object where to find this nib file so that it can load it. In applications based on either AppKit and UIKit, this configuration data is located in the application’s Info.plist file. When an application is first loaded, the default application startup code looks in the Info.plist file for the NSMainNibFile key. If it findsit, it looksin the application bundle for a nib file whose name (with or without the filename extension) matches the value of that key and loads it. Each View Controller Manages its Own Nib File The UIViewController (iOS) and NSViewController (OS X) classessupport the automatic loading of their associated nib file. If you specify a nib file when creating the view controller, that nib file isloaded automatically when you try to access the view controller’s view. Any connections between the view controller and the nib file objects are created automatically, and in iOS, the UIViewController object also receives additional notifications when the views are finally loaded and displayed on screen. To help manage memory better, the UIViewController class also handles the unloading of its nib file (as appropriate) during low-memory conditions. For more information about how you use the UIViewController class and how you configure it, see View Controller Programming Guide for iOS . Document and Window Controllers Load Their Associated Nib File In the AppKit framework, the NSDocument class works with the default window controller to load the nib file containing your document window. The windowNibName method of NSDocument is a convenience method that you can use to specify the nib file containing the corresponding document window. When a new document is created, the document object passes the nib file name you specify to the default window controller object, which loads and manages the contents of the nib file. If you use the standard templates provided by Xcode, the only thing you have to do is add the contents of your document window to the nib file. The NSWindowController class also provides automatic support for loading nib files. If you create custom window controllers programmatically, you have the option of initializing them with an NSWindow object or with the name of a nib file. If you choose the latter option, the NSWindowController class automatically loads the specified nib file the first time a client tries to access the window. After that, the window controller keeps the window around in memory; it does not reload it from the nib file, even if the window’s “Release when closed” attribute is set. Nib Files Built-In Support For Nib Files 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 22Important: When using either NSWindowController or NSDocument to load windows automatically, it is important that your nib file be configured correctly. Both classes include a window outlet that you must connect to the window you want them to manage. If you do not connect this outlet to a window object, the nib file is loaded but the document or window controller does not display the window. For more information about the Cocoa document architecture, see Document-Based App Programming Guide for Mac . Loading Nib Files Programmatically Both OS X and iOS provide convenience methods for loading nib files into your application. Both the AppKit and UIKit framework define additional methods on the NSBundle class that support the loading of nib files. In addition, the AppKit framework also provides the NSNib class, which provides similar nib-loading behavior as NSBundle but offers some additional advantages that might be useful in specific situations. As you plan out your application, make sure any nib files you plan to load manually are configured in a way that simplifies the loading process. Choosing an appropriate object for File’s Owner and keeping your nib files small can greatly improve their ease of use and memory efficiency. For more tips on configuring your nib files, see “Nib File Design Guidelines” (page 11). Loading Nib Files Using NSBundle The AppKit and UIKit frameworks define additional methods on the NSBundle class (using Objective-C categories) to support the loading of nib file resources. The semantics for how you use the methods differs between the two platforms as doesthe syntax for the methods. In AppKit, there are more optionsfor accessing bundles in general and so there are correspondingly more methods for loading nib files from those bundles. In UIKit, applications can load nib files only from their main bundle and so fewer options are needed. The methods available on the two platforms are as follows: ● AppKit ● loadNibNamed:owner: class method ● loadNibFile:externalNameTable:withZone: class method ● loadNibFile:externalNameTable:withZone: instance method ● UIKit ● loadNibNamed:owner:options: instance method Nib Files Loading Nib Files Programmatically 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 23Whenever loading a nib file, you should always specify an object to act as File’s Owner of that nib file. The role of the File’s Owner is an important one. It is the primary interface between your running code and the new objects that are about to be created in memory. All of the nib-loading methods provide a way to specify the File’s Owner, either directly or as a parameter in an options dictionary. One of the semantic differences between the way the AppKit and UIKit frameworks handle nib loading is the way the top-level nib objects are returned to your application. In the AppKit framework, you must explicitly request them using one of the loadNibFile:externalNameTable:withZone: methods. In UIKit, the loadNibNamed:owner:options: method returns an array of these objects directly. The simplest way to avoid having to worry about the top-level objects in either case is to store them in outlets of your File’s Owner object and to make sure the setter methods for those outlets retain their values. Because each platform uses different retain semantics, however, you must be sure to send the proper retain or release messages when appropriate. For information about the retention semantics for nib objects, see “Managing the Lifetimes of Objects from Nib Files” (page 15). Listing 1-1 shows a simple example of how to load a nib file using the NSBundle class in an AppKit–based application. As soon as the loadNibNamed:owner: method returns, you can begin using any outlets that refer to the nib file objects. In other words, the entire nib-loading process occurs within the confines of that single call. The nib-loading methods in the AppKit framework return a Boolean value to indicate whether the load operation was successful. Listing 1-1 Loading a nib file from the current bundle - (BOOL)loadMyNibFile { // The myNib file must be in the bundle that defines self's class. if (![NSBundle loadNibNamed:@"myNib" owner:self]) { NSLog(@"Warning! Could not load myNib file.\n"); return NO; } return YES; } Listing 1-2 shows an example of how to load a nib file in a UIKit–based application. In this case, the method checks the returned array to see if the nib objects were loaded successfully. (Every nib file should have at least one top-level object representing the contents of the nib file.) This example shows the simple case when the nib file contains no placeholder objects other than the File’s Owner object. For an example of how to specify additional placeholder objects, see “Replacing Proxy Objects at Load Time” (page 28). Nib Files Loading Nib Files Programmatically 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 24Listing 1-2 Loading a nib in an iPhone application - (BOOL)loadMyNibFile { NSArray* topLevelObjs = nil; topLevelObjs = [[NSBundle mainBundle] loadNibNamed:@"myNib" owner:self options:nil]; if (topLevelObjs == nil) { NSLog(@"Error! Could not load myNib file.\n"); return NO; } return YES; } Note: If you are developing a Universal application for iOS, you can use the device-specific naming conventionsto load the correct nib file for the underlying device automatically. For more information about how to name your nib files, see “iOS Supports Device-Specific Resources” (page 7). Getting a Nib File’s Top-Level Objects The easiest way to get the top-level objects of your nib file is to define outlets in the File’s Owner object along with setter methods (or better yet, properties) for accessing those objects. This approach ensures that the top-level objects are retained by your object and that you always have references to them. Listing 1-3 shows the interface and implementation of a simplified Cocoa class that uses an outlet to retain the nib file’s only top-level object. In this case, the only top-level object in the nib file is an NSWindow object. Because top-level objects in Cocoa have an initial retain count of 1, an extra release message is included. This is fine because by the time the release call is made, the property has already been retained the window. You would not want to release top-level objects in this manner in an iPhone application. Listing 1-3 Using outlets to get the top-level objects // Class interface @interface MyController : NSObject { NSWindow *window; } Nib Files Loading Nib Files Programmatically 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 25@property(retain) IBOutlet NSWindow *window; - (void)loadMyWindow; @end // Class implementation @implementation MyController // The synthesized property retains the window automatically. @synthesize window; - (void)loadMyWindow { [NSBundle loadNibNamed:@"myNib" owner:self]; // The window starts off with a retain count of 1 // and is then retained by the property, so add an extra release. [window release]; } @end If you do not want to use outlets to store references to your nib file’s top-level objects, you must retrieve those objects manually in your code. The technique for obtaining the top-level objects differs depending on the target platform. In OS X, you must ask for the objects explicitly, whereas in iOS they are returned to you automatically. Listing 1-4 showsthe processfor getting the top-level objects of a nib file in OS X. This method places a mutable array into the nameTable dictionary and associatesit with the NSNibTopLevelObjects key. The nib-loading code looks for this array object and, if present, places the top-level objects in it. Because each object starts with a retain count of 1 before it is added to the array, simply releasing the array is not enough to release the objects in the array as well. As a result, this method sends a release message to each of the objects to ensure that the array is the only entity holding a reference to them. Listing 1-4 Getting the top-level objects from a nib file at runtime - (NSArray*)loadMyNibFile { Nib Files Loading Nib Files Programmatically 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 26NSBundle* aBundle = [NSBundle mainBundle]; NSMutableArray* topLevelObjs = [NSMutableArray array]; NSDictionary* nameTable = [NSDictionary dictionaryWithObjectsAndKeys: self, NSNibOwner, topLevelObjs, NSNibTopLevelObjects, nil]; if (![aBundle loadNibFile:@"myNib" externalNameTable:nameTable withZone:nil]) { NSLog(@"Warning! Could not load myNib file.\n"); return nil; } // Release the objects so that they are just owned by the array. [topLevelObjs makeObjectsPerformSelector:@selector(release)]; return topLevelObjs; } Obtaining the top-level objects in an iPhone application is much simpler and is shown in Listing 1-2 (page 25). In the UIKit framework, the loadNibNamed:owner:options: method of NSBundle automatically returns an array with the top-level objects. In addition, by the time the array is returned, the retain counts on the objects are adjusted so that you do not need to send each object an extra release message. The returned array is the only owner of the objects. Loading Nib Files Using UINib and NSNib The UINib (iOS) and NSNib (OS X) classes provide better performance in situations where you want to create multiple copies of a nib file’s contents. The normal nib-loading process involves reading the nib file from disk and then instantiating the objects it contains. However, with the UINib and NSNib classes, the nib file is read from disk once and the contents are stored in memory. Because they are in memory, creating successive sets of objects takes less time because it does not require accessing the disk. Using the UINib and NSNib classes is always a two-step process. First, you create an instance of the class and initialize it with the nib file’s location information. Second, you instantiate the contents of the nib file to load the objects into memory. Each time you instantiate the nib file, you specify a different File’s Owner object and receive a new set of top-level objects. Nib Files Loading Nib Files Programmatically 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 27Listing 1-5 shows one way to load the contents of a nib file using the NSNib class in OS X. The array returned to you by the instantiateNibWithOwner:topLevelObjects: method comes already autoreleased. If you intend to use that array for any period of time, you should make a copy of it. Listing 1-5 Loading a nib file using NSNib - (NSArray*)loadMyNibFile { NSNib* aNib = [[NSNib alloc] initWithNibNamed:@"MyPanel" bundle:nil]; NSArray* topLevelObjs = nil; if (![aNib instantiateNibWithOwner:self topLevelObjects:&topLevelObjs]) { NSLog(@"Warning! Could not load nib file.\n"); return nil; } // Release the raw nib data. [aNib release]; // Release the top-level objects so that they are just owned by the array. [topLevelObjs makeObjectsPerformSelector:@selector(release)]; // Do not autorelease topLevelObjs. return topLevelObjs; } Replacing Proxy Objects at Load Time In iOS, it is possible to create nib files that include placeholder objects besides the File’s Owner. Proxy objects represent objects created outside of the nib file but which have some connection to the nib file’s contents. Proxies are commonly used to support navigation controllers in iPhone applications. When working with navigation controllers, you typically connect the File’s Owner object to some common object such as your application delegate. Proxy objects therefore represent the parts of the navigation controller object hierarchy that are already loaded in memory, because they were created programmatically or loaded from a different nib file. Nib Files Loading Nib Files Programmatically 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 28Note: Custom placeholder objects (other than File’s Owner) are not supported in OS X nib files. Each placeholder object you add to a nib file must have a unique name. To assign a name to an object, select the object in Xcode and open the inspector window. The Attributes pane of the inspector contains a Name field, which you use to specify the name for your placeholder object. The name you assign should be descriptive of the object’s behavior or type, but really it can be anything you want. When you are ready to load a nib file containing placeholder objects, you mustspecify the replacement objects for any proxies when you call the loadNibNamed:owner:options: method. The options parameter of this method accepts a dictionary of additional information. You use this dictionary to pass in the information about your placeholder objects. The dictionary must contain the UINibExternalObjects key whose value is another dictionary containing the name and object for each placeholder replacement. Listing 1-6 shows a sample version of an applicationDidFinishLaunching: method that loads the application’s main nib file manually. Because the application’s delegate object is created by the UIApplicationMain function, this method uses a placeholder (with the name “AppDelegate”) in the main nib file to represent that object. The proxies dictionary stores the placeholder object information and the options dictionary wraps that dictionary. Listing 1-6 Replacing placeholder objects in a nib file - (void)applicationDidFinishLaunching:(UIApplication *)application { NSArray* topLevelObjs = nil; NSDictionary* proxies = [NSDictionary dictionaryWithObject:self forKey:@"AppDelegate"]; NSDictionary* options = [NSDictionary dictionaryWithObject:proxies forKey:UINibExternalObjects]; topLevelObjs = [[NSBundle mainBundle] loadNibNamed:@"Main" owner:self options:options]; if ([topLevelObjs count] == 0) { NSLog(@"Warning! Could not load myNib file.\n"); return; } // Show window [window makeKeyAndVisible]; Nib Files Loading Nib Files Programmatically 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 29} For more information about the options dictionary of the loadNibNamed:owner:options: method, see NSBundle UIKit Additions Reference . Accessing the Contents of a Nib File Upon the successful loading a nib file, its contents become ready for you to use immediately. If you configured outlets in your File’s Owner to point to nib file objects, you can now use those outlets. If you did not configure your File’s Owner with any outlets, you should make sure you obtain a reference to the top-level objects in some manner so that you can release them later. Because outlets are populated with real objects when a nib file is loaded, you can subsequently use outlets as you would any other object you created programmatically. For example, if you have an outlet pointing to a window, you could send that window a makeKeyAndOrderFront: message to show it on the user’s screen. When you are done using the objects in your nib file, you must release them like any other objects. Important: You are responsible for releasing the top-level objects of any nib files you load when you are finished with those objects. Failure to do so is a cause of memory leaksin many applications. After releasing the top-level objects, it is a good idea to clear any outlets pointing to objects in the nib file by setting them to nil. You should clear outlets associated with all of the nib file’s objects, not just the top-level objects. Connecting Menu Items Across Nib Files The items in an OS X application’s menu bar often need to interact with many different objects, including your application’s documents and windows. The problem is that many of these objects cannot (or should not) be accessed directly from the main nib file. The File’s Owner of the main nib file is always set to an instance of the NSApplication class. And although you might be able to instantiate a number of custom objects in your main nib file, doing so is hardly practical or necessary. In the case of document objects, connecting directly to a specific document object is not even possible because the number of document objects can change dynamically and can even be zero. Most menu items send action messages to one of the following: ● A fixed object that always handles the command ● A dynamic object, such as a document or window Nib Files Connecting Menu Items Across Nib Files 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 30Messaging fixed objects is a relatively straightforward process that is usually best handled through the application delegate. The application delegate object assiststhe NSApplication objectin running the application and is one of the few objects that rightfully belongs in the main nib file. If the menu item refers to an application-level command, you can implement that command directly in the application delegate or just have the delegate forward the message to the appropriate object elsewhere in your application. If you have a menu item that acts on the contents of the frontmost window, you need to link the menu item to the First Responder placeholder object. If the action method associated with the menu item is specific to one of your objects(and not defined by Cocoa), you must add that action to the First Responder before creating the connection. After creating the connection, you need to implement the action method in your custom class. That object should also implement the validateMenuItem: method to enable the menu item at appropriate times. For more information about how the responder chain handles commands, see Cocoa Event Handling Guide . Nib Files Connecting Menu Items Across Nib Files 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 31An important part of the localization process is to localize all of the text strings displayed by your application. By their nature, strings located in nib files can be readily localized along with the rest of the nib file contents. Strings embedded in your code, however, must be extracted, localized, and then reinserted back into your code. To simplify this process—and to make the maintenance of your code easier—OS X and iOS provide the infrastructure needed to separate strings from your code and place them into resource files where they can be localized easily. Resource filesthat contain localizable strings are referred to as strings files because of their filename extension, which is .strings. You can create strings files manually or programmatically depending on your needs. The standard strings file format consists of one or more key-value pairs along with optional comments. The key and value in a given pair are strings of text enclosed in double quotation marks and separated by an equal sign. (You can also use a property list format for strings files. In such a case, the top-level node is a dictionary and each key-value pair of that dictionary is a string entry.) Listing 2-1 shows a simple strings file that contains non-localized entries for the default language. When you need to display a string, you pass the string on the left to one of the available string-loading routines. What you get back isthe matching value string containing the text translation that is most appropriate for the current user. For the development language, it is common to use the same string for both the key and value, but doing so is not required. Listing 2-1 A simple strings file /* Insert Element menu item */ "Insert Element" = "Insert Element"; /* Error string used for unknown error types. */ "ErrorString_1" = "An unknown error occurred."; A typical application has at least one strings file per localization, that is, one strings file in each of the bundle’s .lproj subdirectories. The name of the default strings file is Localizable.strings but you can create stringsfiles with any file name you choose. Creating stringsfilesis discussed in more depth in “Creating Strings Resource Files” (page 33). 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 32 String ResourcesNote: It is recommended that you save strings files using the UTF-16 encoding, which is the default encoding forstandard stringsfiles. It is possible to create stringsfiles using other property-list formats, including binary property-list formats and XML formats that use the UTF-8 encoding, but doing so is not recommended. For more information about the standard strings file format, see “Creating Strings Resource Files” (page 33). For more information about Unicode and its text encodings, go to http://www.unicode.org/ or http://en.wikipedia.org/wiki/Unicode. The loading of string resources (both localized and nonlocalized) ultimately relies on the bundle and internationalization supportfound in bothOS X and iOS. Forinformation about bundles,see Bundle Programming Guide . For more information about internationalization and localization,see Internationalization Programming Topics. Creating Strings Resource Files Although you can create strings files manually, it is rarely necessary to do so. The easiest way to create strings files is to write your code using the appropriate string-loading macros and then use the genstrings command-line tool to extract those strings and create strings files for you. The following sections describe the process of how to set up your source files to facilitate the use of the genstrings tool. For detailed information about the tool, see genstrings man page. Choosing Which Strings to Localize When it comes to localizing your application’s interface, it is not always appropriate to localize every string used by your application. Translation is a costly process, and translating strings that are never seen by the user is a waste of time and money. Strings that are not displayed to the user, such as notification names used internally by your application, do not need to be translated. Consider the following example: if (CFStringHasPrefix(value, CFSTR("-")) { CFArrayAppendValue(myArray, value);}; In this example, the string “-” is used internally and is never seen by the user; therefore, it does not need to be placed in a strings file. The following code shows another example of a string the user would not see. The string "%d %d %s" does not need to be localized, since the user never sees it and it has no effect on anything that the user does see. matches = sscanf(s, "%d %d %s", &first, &last, &other); String Resources Creating Strings Resource Files 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 33Because nib files are localized separately, you do not need to include strings that are already located inside of a nib file. Some of the strings you should localize, however, include the following: ● Strings that are programmatically added to a window, panel, view, or control and subsequently displayed to the user. This includes strings you pass into standard routines, such as those that display alert boxes. ● Menu item title strings if those strings are added programmatically. For example, if you use custom strings for the Undo menu item, those strings should be in a strings file. ● Error messages that are displayed to the user. ● Any boilerplate text that is displayed to the user. ● Some stringsfromyour application’sinformation property list(Info.plist) file;see Runtime Configuration Guidelines. ● New file and document names. About the String-Loading Macros The Foundation and Core Foundation frameworks define the following macros to make loading strings from a strings file easier: ● Core Foundation macros: ● CFCopyLocalizedString ● CFCopyLocalizedStringFromTable ● CFCopyLocalizedStringFromTableInBundle ● CFCopyLocalizedStringWithDefaultValue ● Foundation macros: ● NSLocalizedString ● NSLocalizedStringFromTable ● NSLocalizedStringFromTableInBundle ● NSLocalizedStringWithDefaultValue You use these macrosin yoursource code to load stringsfrom one of your application’sstringsfiles. The macros take the user’s current language preferences into account when retrieving the actual string value. In addition, the genstrings tool searches for these macros and uses the information they contain to build the initial set of strings files for your application. For additional information about how to use these macros,see “Loading String ResourcesInto Your Code” (page 37). String Resources Creating Strings Resource Files 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 34Using the genstrings Tool to Create Strings Files At some point during your development, you need to create the strings files needed by your code. If you wrote your code using the Core Foundation and Foundation macros, the simplest way to create your strings files is using the genstrings command-line tool. You can use thistool to generate a new set ofstringsfiles or update a set of existing files based on your source code. To use the genstrings tool, you typically provide at least two arguments: ● A list of source files ● An optional output directory The genstrings tool can parse C, Objective-C, and Java code files with the .c, .m, or .java filename extensions. Although not strictly required, specifying an output directory is recommended and is where genstrings places the resulting strings files. In most cases, you would want to specify the directory containing the project resources for your development language. The following example shows a simple command for running the genstrings tool. This command causes the tool to parse all Objective-C source files in the current directory and put the resulting strings files in the en.lproj subdirectory, which must already exist. genstrings -o en.lproj *.m The first time you run the genstrings tool, it creates a set of new stringsfilesfor you. Subsequent runsreplace the contents of those strings files with the current string entries found in your source code. For subsequent runs, it is a good idea to save a copy of your current strings files before running genstrings. You can then diff the new and old versions to determine which strings were added to (or changed in) your project. You can then use this information to update any already localized versions of your strings files, rather than replacing those files and localizing them again. Within a single strings file, each key must be unique. Fortunately, the genstrings tool is smart enough to coalesce any duplicate entries it finds. When it discovers a key string used more than once in a single strings file, the tool merges the comments from the individual entries into one comment string and generates a warning. (You can suppressthe duplicate entries warning with the -q option.) If the same key string is assigned to strings in different strings files, no warning is generated. For more information about using the genstrings tool, see the genstrings man page. String Resources Creating Strings Resource Files 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 35Creating Strings Files Manually Although the genstrings tool is the most convenient way to create strings files, you can also create them manually. To create a stringsfile manually, create a new file in TextEdit (or your preferred text-editing application) and save it using the Unicode UTF-16 encoding. (When saving files, TextEdit usually chooses an appropriate encoding by default. To force a specific encoding, you must change the save options in the application preferences.) The contents of thisfile consists of a set of key-value pairs along with optional comments describing the purpose of each key-value pair. Key and value strings are separated by an equal sign, and the entire entry must be terminated with a semicolon character. By convention, comments are enclosed inside C-style comment delimiters (/* and */) and are placed immediately before the entry they describe. Listing 2-2 shows the basic format of a strings file. The entries in this example come from the English version of the Localizable.strings file from the TextEdit application. The string on the left side of each equal sign representsthe key, and the string on the rightside representsthe value. A common convention when developing applications is to use a key name that equals the value in the language used to develop the application. Therefore, because TextEdit was developed using the English language, the English version of the Localizable.strings file has keys and values that match. Listing 2-2 Strings localized for English /* Menu item to make the current document plain text */ "Make Plain Text" = "Make Plain Text"; /* Menu item to make the current document rich text */ "Make Rich Text" = "Make Rich Text"; Listing 2-3 shows the German translation of the same entries. These entries also live inside a file called Localizable.strings, but this version of the file is located in the German language project directory of the TextEdit application. Notice that the keys are still in English, but the values assigned to those keys are in German. This is because the key strings are never seen by end users. They are used by the code to retrieve the corresponding value string, which in this case is in German. Listing 2-3 Strings localized for German /* Menu item to make the current document plain text */ "Make Plain Text" = "In reinen Text umwandeln"; /* Menu item to make the current document rich text */ "Make Rich Text" = "In formatierten Text umwandeln"; String Resources Creating Strings Resource Files 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 36Detecting Non-localizable Strings AppKit–based applications can take advantage of built-in support to detect strings that do not need to be localized and those that need to be localized but currently are not. To use this built-in support, you must launch your application from the command line. In addition to entering the path to your executable, you must also include the name of the desired setting along with a Boolean value to indicate whether the setting should be enabled or disabled. The available settings are as follows: ● The NSShowNonLocalizableStrings setting identifies strings that are not localizable. The strings are logged to the shell in upper case. This option occasionally generates some false positives but is still useful overall. ● The NSShowNonLocalizedStrings setting locates strings that were meant to be localized but could not be found in the application’s existing strings files. You can use this setting to catch problems with out-of-date localizations. For example, to use the NSShowNonLocalizedStrings setting with the TextEdit application, you would enter the following in Terminal: /Applications/TextEdit.app/Contents/MacOS/TextEdit -NSShowNonLocalizedStrings YES Loading String Resources Into Your Code The Core Foundation and Foundation frameworks provide macrosfor retrieving both localized and nonlocalized strings stored in strings files. Although the main purpose of these macros is to load strings at runtime, they also serve a secondary purpose by acting as markers that the genstrings tool can use to locate your application’s string resources. It is this second purpose that explains why many of the macros let you specify much more information than would normally be required for loading a string. The genstrings tool uses the information you provide to create or update your application’s strings files automatically. Table 2-1 lists the types of information you can specify for these routines and describes how that information is used by the genstrings tool. Table 2-1 Common parameters found in string-loading routines Parameter Description The string used to look up the corresponding value. This string must not contain any characters from the extended ASCII character set, which includes accented versions of ASCII characters. If you want the initial value string to contain extended ASCII characters, use a routine that lets you specify a default value parameter. (For information about the extended ASCII character set, see the corresponding Wikipedia entry.) Key String Resources Loading String Resources Into Your Code 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 37Parameter Description The name of the strings file in which the specified key is located. The genstrings tool interprets this parameter as the name of the strings file in which the string should be placed. If no table name is provided, the string is placed in the default Localizable.strings file. (When specifying a value for this parameter, include the filename without the .strings extension.) Table name The default value to associate with a given key. If no default value is specified, the genstrings tool uses the key string as the initial value. Default value strings may contain extended ASCII characters. Default value Translation comments to include with the string. You can use comments to provide clues to the translation team about how a given string is used. The genstrings tool putsthese commentsin the stringsfile and enclosesthem in C-style comment delimiters (/* and */) immediately above the associated entry. Comment An NSBundle object or CFBundleRef type corresponding to the bundle containing the stringsfile. You can use thisto load stringsfrom bundles other than your application’s main bundle. For example, you might use this to load localized strings from a framework or plug-in. Bundle When you request a string from a strings file, the string that is returned depends on the available localizations (if any). The Cocoa and Core Foundation macros use the built-in bundle internationalization support to retrieve the string whose localization matchesthe user’s current language preferences. Aslong as your localized resource files are placed in the appropriate language-specific project directories, loading a string with these macros should yield the appropriate string automatically. If no appropriate localized string resource is found, the bundle’s loading code automatically chooses the appropriate nonlocalized string instead. For information about internationalization in general and how to create language-specific project directories, see Internationalization Programming Topics. For information about the bundle structure and how resource files are chosen from a bundle directory, see Bundle Programming Guide . Using the Core Foundation Framework The Core Foundation framework defines a single function and several macrosfor loading localized stringsfrom your application bundle. The CFBundleCopyLocalizedString function provides the basic implementation for retrieving the strings. However, it is recommended that you use the following macros instead: ● CFCopyLocalizedString(key, comment) ● CFCopyLocalizedStringFromTable(key, tableName, comment) ● CFCopyLocalizedStringFromTableInBundle(key, tableName, bundle, comment) String Resources Loading String Resources Into Your Code 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 38● CFCopyLocalizedStringWithDefaultValue(key, tableName, bundle, value, comment) There are several reasons to use the macros instead of the CFBundleCopyLocalizedString function. First, the macros are easier to use for certain common cases. Second, the macros let you associate a comment string with the string entry. Third, the macros are recognized by the genstrings tool but the CFBundleCopyLocalizedString function is not. For information about the syntax of the preceding macros, see CFBundle Reference . Using the Foundation Framework The Foundation framework defines a single method and several macros for loading string resources. The localizedStringForKey:value:table: method of the NSBundle classloadsthe specified string resource from a strings file residing in the current bundle. Cocoa also defines the following macros for getting localized strings: ● NSLocalizedString(key, comment) ● NSLocalizedStringFromTable(key, tableName, comment) ● NSLocalizedStringFromTableInBundle(key, tableName, bundle, comment) ● NSLocalizedStringWithDefaultValue(key, tableName, bundle, value, comment) As with Core Foundation, Apple recommends that you use the Cocoa convenience macros for loading strings. The main advantage to these macros is that they can be parsed by the genstrings tool and used to create your application’s strings files. They are also simpler to use and let you associate translation comments with each entry. For information about the syntax of the preceding macros, see Foundation Functions Reference . Additional methods for loading strings are also defined in NSBundle Class Reference . Examples of Getting Strings The following examples demonstrate the basic techniques for using the Foundation and Core Foundation macros to retrieve strings. Each example assumes that the current bundle contains a strings file with the name Custom.strings that has been translated into French. This translated file includes the following strings: /* A comment */ "Yes" = "Oui"; "The same text in English" = "Le même texte en anglais"; String Resources Loading String Resources Into Your Code 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 39Using the Foundation framework, you can get the value of the “Yes” string using the NSLocalizedStringFromTable macro, as shown in the following example: NSString* theString; theString = NSLocalizedStringFromTable (@"Yes", @"Custom", @"A comment"); Using the Core Foundation framework, you could get the same string using the CFCopyLocalizedStringFromTable macro, as shown in this example: CFStringRef theString; theString = CFCopyLocalizedStringFromTable(CFSTR("Yes"), CFSTR("Custom"), "A comment"); In both examples, the code specifies the key to retrieve, which is the string “Yes”. They also specify the strings file (or table) in which to look for the key, which in this case isthe Custom.strings file. During string retrieval, the comment string is ignored. Advanced Strings File Tips The following sections provide some additional tips for working with strings files and string resources. Searching for Custom Functions With genstrings The genstrings tool searches for the Core Foundation and Foundation string macros by default. It uses the information in these macros to create the string entries in your project’s strings files. You can also direct genstrings to look for custom string-loading functions in your code and use those functions in addition to the standard macros. You might use custom functionsto wrap the built-in string-loading routines and perform some extra processing or you might replace the defaultstring handling behavior with your own custom model. If you want to use genstrings with your own custom functions, your functions must use the naming and formatting conventions used by the Foundation macros. The parameters for your functions must match the parameters for the corresponding macros exactly. When you invoke genstrings, you specify the -s option followed by the name of the function that correspondsto the NSLocalizedString macro. Your other function names should then build from this base name. For example, if you specified the function name MyStringFunction, your other function names should be MyStringFunctionFromTable, MyStringFunctionFromTableInBundle, and MyStringFunctionWithDefaultValue. The genstrings tool looks for these functions and uses them to build the corresponding strings files. String Resources Advanced Strings File Tips 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 40Formatting String Resources For some strings, you may not want to (or be able to) encode the entire string in a string resource because portions of the string might change at runtime. For example, if a string contains the name of a user document, you need to be able to insert that document name into the string dynamically. When creating your string resources, you can use any of the formatting characters you would normally use for handling string replacement in the Foundation and Core Foundation frameworks. Listing 2-4 shows several string resources that use basic formatting characters: Listing 2-4 Strings with formatting characters "Windows must have at least %d columns and %d rows." = "Les fenêtres doivent être composes au minimum de %d colonnes et %d lignes."; "File %@ not found." = "Le fichier %@ n’existe pas."; To replace formatting characters with actual values, you use the stringWithFormat: method of NSString or the CFStringCreateWithFormat function, using the string resource as the format string. Foundation and Core Foundation support most of the standard formatting characters used in printf statements. In addition, you can use the %@ specifiershown in the preceding example to insert the descriptive text associated with arbitrary Objective-C objects. See “Formatting String Objects” in String Programming Guide for the complete list of specifiers. One problem that often occurs during translation is that the translator may need to reorder parameters inside translated strings to account for differences in the source and target languages. If a string contains multiple arguments, the translator can insert special tags of the form n$ (where n specifies the position of the original argument) in between the formatting characters. These tags let the translator reorder the arguments that appear in the original string. The following example shows a string whose two arguments are reversed in the translated string: /* Message in alert dialog when something fails */ "%@ Error! %@ failed!" = "%2$@ blah blah, %1$@ blah!"; Using Special Characters in String Resources Just as in C, some characters must be prefixed with a backslash before you can include them in the string. These characters include double quotation marks, the backslash character itself, and special control characters such as linefeed (\n) and carriage returns (\r). "File \"%@\" cannot be opened" = " ... "; "Type \"OK\" when done" = " ... "; String Resources Advanced Strings File Tips 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 41You can include arbitrary Unicode characters in a value string by specifying \U followed immediately by up to four hexadecimal digits. The four digits denote the entry for the desired Unicode character; for example, the space character is represented by hexadecimal 20 and thus would be \U0020 when specified as a Unicode character. This option is useful if a string must include Unicode characters that for some reason cannot be typed. If you use this option, you must also pass the -u option to genstrings in order for the hexadecimal digits to be interpreted correctly in the resulting strings file. The genstrings tool assumes your strings are low-ASCII by default and only interprets backslash sequences if the -u option is specified. Note: The genstrings tool always generatesstringsfiles using the UTF-16 encoding. If you include Unicode characters in your strings and do not use genstrings to create your strings files, be sure to save your strings files in the UTF-16 encoding. Debugging Strings Files If you run into problems during testing and find that the functions and macros for retrieving strings are always returning the same key (as opposed to the translated value), run the /usr/bin/plutil tool on your strings file. A strings file is essentially a property-list file formatted in a special way. Running plutil with the -lint option can uncover hidden characters or other errorsthat are preventing stringsfrom being retrieved correctly. String Resources Advanced Strings File Tips 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 42The OS X and iOS platforms were built to provide a rich multimedia experience. To support that experience, both platforms provide plenty of support for loading and using image, sound, and video resources in your application. Image resources are commonly used to draw portions of an application’s user interface. Sound and video resources are used less frequently but can also enhance the basic appearance and appeal of an application. The following sections describe the support available for working with image, sound, and video resources in your applications. Images and Sounds in Nib Files Using Xcode, you can reference your application’s sound and image files from within nib files. You might do so to associate those images or sounds with different properties of a view or control. For example, you might set the default image to display in an image view or set the image to display for a button. Creating such a connection in a nib file saves you the hassle of having to make that connection later when the nib file isloaded. To make image and sound resources available in a nib file, all you have to do is add them to your Xcode project; Xcode then lists them in the library pane. When you make a connection to a given resource file, Xcode makes a note of that connection in the nib file. At load time, the nib-loading code looksfor that resource in the project bundle, where it should have been placed by Xcode at build time. When you load a nib file that contains references to image and sound resources, the nib-loading code caches resources whenever possible for easy retrieval later. For example, after loading a nib file, you can retrieve an image associated with that nib file using the imageNamed: method of either NSImage or UIImage (depending on your platform). In OS X you can retrieve cached sound resources using the soundNamed: method of NSSound. Loading Image Resources Image resources are commonly used in most applications. Even very simple applications use images to create a custom look for controls and views. OS X and iOS provide extensive support for manipulating image data using Objective-C objects. These objects make using image images extremely easy, often requiring only a few 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 43 Image, Sound, and Video Resourceslines of code to load and draw the image. If you prefer not to use the Objective-C objects, you can also use Quartz to load images using a C-based interface. The following sections describe the processfor loading image resource files using each of the available techniques. Loading Images in Objective-C To load images in Objective-C, you use either the NSImage or UIImage object, depending on the current platform. Applications built for OS X using the AppKit framework use the NSImage object to load images and draw them. Applications built for iOS use the UIImage object. Functionally, both of these objects provide almost identical behavior when it comesto loading existing image resources. You initialize the object by passing it a pointer to the image file in your application bundle and the image object takes care of the details of loading the image data. Listing 3-1 shows how to load an image resource using the NSImage class in OS X. After you locate the image resource, which in this case is in the application bundle, you simply use that path to initialize the image object. After initialization, you can draw the image using the methods of NSImage or passthat object to other methods that can use it. To perform the exactsame task in iOS, all you would need to do is change references of NSImage to UIImage. Listing 3-1 Loading an image resource NSString* imageName = [[NSBundle mainBundle] pathForResource:@"image1" ofType:@"png"]; NSImage* imageObj = [[NSImage alloc] initWithContentsOfFile:imageName]; You can use image objectsto open any type of image supported on the target platform. Each object istypically a lightweight wrapper for more advanced image handling code. To draw an image in the current graphics context, you would simply use one of its drawing related methods. Both NSImage and UIImage have methods for drawing the image in several different ways. The NSImage class also provides extra support for manipulating the images you load. For information about the methods of the NSImage and UIImage classes, see NSImage Class Reference and UIImage Class Reference . For more detailed information about the additional features of the NSImage class, see “Images” in Cocoa Drawing Guide . Image, Sound, and Video Resources Loading Image Resources 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 44Loading Images Using Quartz If you are writing C-based code, you can use a combination of Core Foundation and Quartz calls to load image resources into your applications. Core Foundation provides the initial support for locating image resources and loading the corresponding image data into memory. Quartz takes the image data you load into memory and turns it into a usable CGImageRef that your code can then use to draw the image. There are two ways to load images using Quartz: data providers and image source objects. Data providers are available in both iOS and OS X. Image source objects are available only in OS X v10.4 and later but take advantage of the Image I/O framework to enhance the basic image handling capabilities of data providers. When it comes to loading and displaying image resources, both technologies are well suited for the job. The only time you might prefer image sources over data providers is when you want greater access to the image-related data. Listing 3-2 shows how to use a data provider to load a JPEG image. This method uses the Core Foundation bundle support to locate the image in the application’s main bundle and get a URL to it. It then uses that URL to create the data provider object and then create a CGImageRef for the corresponding JPEG data. (For brevity this example omits any error-handling code. Your own code should make sure that any referenced data structures are valid.) Listing 3-2 Using data providers to load image resources CGImageRef MyCreateJPEGImageRef (const char *imageName); { CGImageRef image; CGDataProviderRef provider; CFStringRef name; CFURLRef url; CFBundleRef mainBundle = CFBundleGetMainBundle(); // Get the URL to the bundle resource. name = CFStringCreateWithCString (NULL, imageName, kCFStringEncodingUTF8); url = CFBundleCopyResourceURL(mainBundle, name, CFSTR("jpg"), NULL); CFRelease(name); // Create the data provider object provider = CGDataProviderCreateWithURL (url); CFRelease (url); // Create the image object from that provider. Image, Sound, and Video Resources Loading Image Resources 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 45image = CGImageCreateWithJPEGDataProvider (provider, NULL, true, kCGRenderingIntentDefault); CGDataProviderRelease (provider); return (image); } For detailed information about working with Quartz images, see Quartz 2D Programming Guide . For reference information about data providers, see Quartz 2D Reference Collection (OS X) or Core Graphics Framework Reference (iOS). Specifying High-Resolution Images in iOS An iOS app should include high-resolution versions of its image resources. When the app is run on a device that has a high-resolution screen, high-resolution images provide extra detail and look better because they do not need to be scaled to fit the space. You provide high-resolution images for each image resource in your application bundle, including icons and launch images. To specify a high-resolution version of an image, create a version whose width and height (measured in pixels) are twice that of the original. You use the extra pixels in the image to provide additional detail. When saving the image, use the same base name but include the string @2x between the base filename and the filename extension. For example, if you have an image named MyImage.png, the name of the high-resolution version would be MyImage@2x.png. Put the high-resolution and original versions of your image in the same location in your application bundle. The bundle- and image-loading routines automatically look for image files with the @2x string when the underlying device has a high-resolution screen. If you combine the @2x string with other modifiers, the @2x string should come before any device modifiers but after all other modifiers, such as launch orientation or URL scheme modifiers. For example: MyImage.png - Default version of an image resource. MyImage@2x.png - High-resolution version of an image resource for devices with Retina displays. MyImage~iphone.png - Version of an image for iPhone and iPod touch. MyImage@2x~iphone.png - High-resolution version of an image for iPhone and iPod touch devices with Retina displays. Image, Sound, and Video Resources Loading Image Resources 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 46When you want to load an image, do not include the @2x or any device modifiers when specifying the image name in your code. For example, if your application bundle included the image files from the preceding list, you would ask for an image named MyImage.png. The system automatically determines which version of the image is most appropriate and loads it. Similarly, when using or drawing that image, you do not have to know whether it is the original resolution or high-resolution version. The image-drawing routines automatically adjust based on the image that wasloaded. However, if you still want to know whether an image isthe original or high-resolution version, you can check its scale factor. If the image is the high-resolution version, its scale factor is set to a value other than 1.0. For more information about how to support high-resolution devices, see “Supporting High-Resolution Screens”. Image, Sound, and Video Resources Loading Image Resources 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 47Separating your application’s data from its code can make it easier to modify your application later. If you store the configuration data for your application in resource files, you can change that configuration without having to recompile your application. Data resource files can be used to store any type of information. The following sections highlight some of the data resource types supported by iOS and OS X. Property List Files Property list files are a way to store custom configuration data outside of your application code. OS X and iOS use property lists extensively to implement features such as user preferences and information property list files for bundles. You can similarly use property lists to store private (or public) configuration data for your applications. A property-list file is essentially a set of structured data values. You can create and edit property lists either programmatically or using the Property List Editor application (located in /Developer/Applications/Utilities). The structure of custom property-list files is completely up to you. You can use property liststo store string, number, Boolean, date, and raw data values. By default, a property list stores data in a single dictionary structure, but you can assign additional dictionaries and arrays as values to create a more hierarchical data set. For information about using property lists,see Property List Programming Guide and Property List Programming Topics for Core Foundation . OS X Data Resource Files Table 4-1 lists some additional resource file types that are supported in Mac apps. 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 48 Data Resource FilesTable 4-1 Other resource types Resource Description Type In OS X, AppleScript terminology and suite files contain information about the scriptability of an application. These files can use the file extensions .sdef, .scriptSuite, or .scriptTerminology. Because the actual AppleScript commands used to script an application are visible in userscripts and the Script Editor application, these resources need to be localized. For information on supporting AppleScript, see AppleScript Overview. AppleScript files In OS X, help content typically consists of a set of HTML files created using a standard text-editing program and registered with the Help Viewer application. (For information on how to register with Help Viewer, see Apple Help Programming Guide .) It is also possible to embed PDF files, RTF files, HTML files or other custom documents in your bundle and open them using an external application, such as Preview or Safari. For information on how to open files, see Launch Services Programming Guide . Help files Data Resource Files OS X Data Resource Files 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 49This table describes the changes to Resource Programming Guide . Date Notes Modified discussion of high-resolution image resources to include all Retina displays. 2012-06-11 2011-10-12 Updated for ARC and iOS 5. Corrected information about how you specify high-resolution image resource filenames. 2010-09-15 2010-05-25 Updated references to the Apple developer website. 2009-01-06 Added information about KVO notifications during nib loading. 2008-06-26 Updated for iOS. Clarified the process of how objects are instantiated when a nib file is loaded. 2007-09-04 Reorganized content and added new information. Changed title from "Loading Resources". 2007-02-08 2005-11-09 Corrected the misidentification of a class method as an instance method. Added “Instantiating Nibs From Memory” and the link to the NSNib class reference. 2003-07-09 2003-05-28 Section on initializing nib file objects corrected and expanded. Revision history was added to existing topic. It will be used to record changes to the content of the topic. 2002-11-12 2012-06-11 | © 2012 Apple Inc. All Rights Reserved. 50 Document Revision HistoryApple Inc. © 2012 Apple Inc. All rights reserved. No part of this publication may be reproduced, stored in a retrievalsystem, or transmitted, in any form or by any means, mechanical, electronic, photocopying, recording, or otherwise, without prior written permission of Apple Inc., with the following exceptions: Any person is hereby authorized to store documentation on a single computer for personal use only and to print copies of documentation for personal use provided that the documentation contains Apple’s copyright notice. No licenses, express or implied, are granted with respect to any of the technology described in this document. Apple retains all intellectual property rights associated with the technology described in this document. This document is intended to assist application developers to develop applications only for Apple-labeled computers. Apple Inc. 1 Infinite Loop Cupertino, CA 95014 408-996-1010 Apple, the Apple logo, AppleScript, Cocoa, iPad, iPhone, iPod, iPod touch, Mac, Objective-C, OS X, Quartz, Safari, and Xcode are trademarks of Apple Inc., registered in the U.S. and other countries. Retina is a trademark of Apple Inc. Java is a registered trademark of Oracle and/or its affiliates. iOS is a trademark or registered trademark of Cisco in the U.S. and other countries and is used under license. Even though Apple has reviewed this document, APPLE MAKES NO WARRANTY OR REPRESENTATION, EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS DOCUMENT, ITS QUALITY, ACCURACY, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.ASARESULT, THISDOCUMENT IS PROVIDED “AS IS,” AND YOU, THE READER, ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND ACCURACY. IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,OR CONSEQUENTIAL DAMAGES RESULTING FROM ANY DEFECT OR INACCURACY IN THIS DOCUMENT, even if advised of the possibility of such damages. THE WARRANTY AND REMEDIES SET FORTH ABOVE ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL OR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer, agent, or employee is authorized to make any modification, extension, or addition to this warranty. Some states do not allow the exclusion or limitation of implied warranties or liability for incidental or consequential damages, so the above limitation or exclusion may not apply to you. This warranty gives you specific legal rights, and you may also have other rights which vary from state to state. Safari CSS Visual Effects GuideContents Introduction 8 At a Glance 9 Use CSS Properties to Add Gradients, Masks, Reflections, and Filters 9 Animate Changes in CSS Properties 9 Apply 2D and 3D Transformations to Any HTML Element 10 How to Use This Document 10 Prerequisites 11 See Also 11 Using Gradients 12 Creating Linear Gradients 12 Setting the Direction of Change 13 Setting the Rate of Change 14 Creating Gradient Fades 16 Creating Radial Gradients 17 Moving the Center 18 Changing the Ending Color Location 19 Adding Color Stops 20 Creating a Radial Fade 22 Creating Repeating Gradients 23 Using a Gradient as a Border Image 24 Prior Syntax (-webkit-gradient) 26 Using Masks 28 Using an Image as a Mask 28 Using a Gradient as a Mask 32 Working with WebKit Mask Properties 35 Using Reflections 37 Adding a Reflection 37 Adjusting the Reflection’s Position 38 Masking a Reflection 39 Inner Reflections 41 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 2Using CSS Filters 43 Using CSS Filters 43 Animating CSS Transitions 45 Setting Transition Properties 46 Using Timing Functions 47 Delaying the Start 48 Setting Several Transition Properties At Once 48 Handling Intermediate States and Events 49 Animating With Keyframes 50 Creating a Keyframe Animation 51 Creating Keyframes 52 Setting Animation Properties 53 Animation Timing Functions 54 Starting Animations 55 Controlling Animation Using JavaScript 56 Handling Animation Events 58 Using 2D and 3D Transforms 61 2D Transform Functions 62 2D Translation 63 2D Rotation 63 2D Scaling 65 Setting Multiple Transforms 66 Changing the Origin 67 3D Transforms 69 Adding 3D Perspective 70 Creating a 3D Space 74 3D Transform Functions 76 Back Face Visibility 80 Using Transformation Matrices 81 2D Matrix Operations 82 3D Matrix Operations 84 Working with Transforms in JavaScript 84 Example: Animated Rotating Box Under JavaScript Control 86 Adding Interactive Control to Visual Effects 90 Using a Click or Tap to Trigger a Transition Effect 90 Controlling a 3D Transform with a Click, Touch, or Swipe 91 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 3 ContentsUsing Gestures to Scale and Rotate Elements 95 Document Revision History 99 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 4 ContentsFigures and Listings Using Gradients 12 Figure 1-1 Simple linear gradient 13 Figure 1-2 Rainbow gradient 13 Figure 1-3 Diagonal gradients 14 Figure 1-4 Setting color stop percentages 15 Figure 1-5 Solid color band and abrupt color change 15 Figure 1-6 Linear gradient fade 16 Figure 1-7 Simple radial gradient 17 Figure 1-8 Circular gradient 18 Figure 1-9 3D lighting effect 19 Figure 1-10 Closest-corner gradient fills 20 Figure 1-11 Multicolor gradient 21 Figure 1-12 Red color stop at 20% 21 Figure 1-13 Color band and abrupt color change using color stops 22 Figure 1-14 Spotlight gradient 23 Figure 1-15 Repeating gradient patterns 24 Figure 1-16 Linear gradient border 25 Figure 1-17 Radial gradient border 26 Listing 1-1 Linear fade 16 Listing 1-2 Radial fade 22 Using Masks 28 Figure 2-1 Heart-shaped “cookie-cutter” 29 Figure 2-2 Masking a border 30 Figure 2-3 Stacking masks 31 Figure 2-4 Applying a mask with a fuzzy border 32 Figure 2-5 Result of applying a gradient mask 33 Figure 2-6 Horizontal gradient mask with color stops 34 Figure 2-7 Masking text with a radial gradient 35 Listing 2-1 Stacking masked elements 30 Using Reflections 37 Figure 3-1 Reflection below a heading 38 Figure 3-2 Reflection with negative offset 39 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 5Figure 3-3 Reflection with image as mask 40 Figure 3-4 Image with reflection and gradient mask 41 Figure 3-5 Inner reflection, reflected 42 Using CSS Filters 43 Figure 4-1 CSS filters on a video 43 Listing 4-1 Applying CSS filters to HTML elements 44 Animating CSS Transitions 45 Figure 5-1 Card Flip example 45 Figure 5-2 Cubic Bezier timing function 47 Figure 5-3 Transition of two properties 49 Listing 5-1 Setting transition properties 46 Listing 5-2 Creating multiple transitions at once 47 Listing 5-3 Defining a custom timing function 48 Listing 5-4 Detecting transition end events 49 Animating With Keyframes 50 Figure 6-1 Animated text elements 50 Figure 6-2 Animation timing function control points 54 Figure 6-3 JavaScript control of animation 58 Listing 6-1 Simple keyframe animation 51 Listing 6-2 Declaring keyframes 52 Listing 6-3 Starting an animation 56 Listing 6-4 Pausing and continuing an animation 57 Listing 6-5 Handling animation events 59 Using 2D and 3D Transforms 61 Figure 7-1 HTML page with rotation and perspective transforms 61 Figure 7-2 A translated element and its offspring 63 Figure 7-3 Rotating an element 64 Figure 7-4 Scaling an element up 66 Figure 7-5 Element rotated around the top-right corner 68 Figure 7-6 3D coordinate space 69 Figure 7-7 Setting the perspective 72 Figure 7-8 Perspective origin effects 74 Figure 7-9 Text rotated relative to 3D backdrop 76 Figure 7-10 Z-axis translation in perspective 78 Figure 7-11 X and y rotation 79 Figure 7-12 Cardflip example 81 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 6 Figures and ListingsFigure 7-13 2D transformation matrix parameter positions 82 Figure 7-14 Matrix mirroring transforms 83 Figure 7-15 3D matrix parameters 84 Figure 7-16 3D transforms under JavaScript control 89 Listing 7-1 Animating 2D rotation 64 Listing 7-2 Setting multiple transforms using a list 67 Listing 7-3 Nesting 2D transforms 67 Listing 7-4 Rotating an element around the top-right corner 68 Listing 7-5 Adding a perspective slider 70 Listing 7-6 Effects of perspective origin 73 Listing 7-7 Nested 3D rotations 75 Listing 7-8 Hiding the back side of a card 80 Listing 7-9 Matrix example 82 Adding Interactive Control to Visual Effects 90 Figure 8-1 Click and tap handler 91 Figure 8-2 Page flip in action 93 Figure 8-3 Element rotated by a gesture 96 Listing 8-1 Simple touch or tap handler 90 Listing 8-2 Page flip on click, tap, or swipe 93 Listing 8-3 Responding to gesture events 96 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 7 Figures and ListingsUse CSS to create stunning visual effects—masks, gradients, reflections, lighting effects, animations, transitions, 3D rotations, and more. Apply any or all of these effects interactively, triggered by mouse events or touch events; make HTML elements visibly respond to the user—without requiring plug-ins, graphics libraries, or elaborate JavaScript programs. There are advantages to using CSS instead of graphic images to create visual effects: ● Because they are resolution-independent, CSS effects scale up smoothly when zoomed. ● Text formatted with CSS is searchable; images are not. ● CSS is compact and compresses well compared with graphic images. ● CSS is just text; it can be quickly modified using a text editor or the output of a script. Safari supports CSS visual effects on Mac OS X and iOS. 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 8 IntroductionAt a Glance Safari CSS visual effectsfall into three categories: new visual CSS properties, animation, and 2D and 3D transforms. Use CSS Properties to Add Gradients, Masks, Reflections, and Filters New visual CSS properties include gradients, masks, reflections, and filters. Gradients let you add beautiful, resolution-independent color blends to backgrounds and borders, with a single line of CSS. Use masks to render portions of HTML elements transparent for elegant compositing. Apply a mask as you would a background or a border image. You can use an image as a mask. You can also use a gradient as a mask, and you can mask any HTML element, not just images. Add a reflection to any element; use a gradient as a mask for a reflection to make the reflection fade to transparency. Filters allow you to add hardware-accelerated visual effects to HTML elements, including images and videos. Relevant chapters: “Using Gradients” (page 12), “Using a Gradient as a Mask” (page 32), “Using Reflections” (page 37), “Using CSS Filters” (page 43). Animate Changes in CSS Properties CSS makes animation easy: specify the properties you want animated, and optionally supply a duration for the animation, and any change to those CSS properties is automatically made into an animation of the HTML element, without using graphic plug-ins or even JavaScript. Use CSS pseudoclasses such as :hover to make the animations interactive—have elements fade in, grow, or enter from offscreen in response to touch or mouse events. CSS animations come in two flavors: implicit animations that render changes smoothly over a defined period, and keyframe animations that allow for more complex behavior, such as moving from side to side or starting and stopping en route. Introduction At a Glance 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 9Relevant chapters: “Animating CSS Transitions” (page 45), “Animating With Keyframes” (page 50). Apply 2D and 3D Transformations to Any HTML Element You can apply 2D or 3D transforms to any HTML element, turning a group of div elements into the faces of a box or the pages of a book, for example. Apply perspective and animation, and you can open and close the box, turn it to look inside, flip the pages of the book, and so on. 2D transforms include scaling, translation, shearing, reflection, and rotation. 3D transforms add rotation about the x and y axis and displacement on the z axis. Add touch and mouse interaction to trigger transformations by implementing CSS pseudoclasses, such as :hover, or by writing your own JavaScript functions. Relevant chapters: “Using 2D and 3D Transforms” (page 61), “Adding Interactive Control to Visual Effects” (page 90). How to Use This Document The visual effects described in this document are WebKit extensions of CSS. Most of the extensions are proposals for W3C standards;some are in W3C draftsfor CSS3. Asthe standards evolve,syntax for these effectsis modified. This change is done carefully to allow new syntax to coexist with existing syntax, however. This means you can experiment with CSS extensions without having your website suddenly break when the standard is modified—in most cases, the old syntax still works. This document describes the current syntax as of this writing; many of the extensions have prior syntax that still works but is no longer recommended. Introduction How to Use This Document 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 10Note: Because these extensions are WebKit-specific, they are not supported in all browsers. Most of the extensions have equivalentsin other WebKit-based browsers, however, and for mobile-specific sites, WebKit-based browsers account for nearly all traffic. Many of the extensions are currently in W3C working drafts and have equivalents in non-WebKit browsers as well, using the same syntax. Nevertheless, unless you are writing an iOS web app, you should code your website to degrade gracefully for browsersthat do notsupport these extensions. For the most part, thisis automatic—an image may not have a reflection in some browsers, or a change in CSS properties may be immediate instead of animated—but the site remains functional and the layout is not broken. As always, you should test your website using all the browsers that you wish to support to ensure that all of your users have an aesthetically pleasing experience. Prerequisites You need a solid understanding of HTML and some familiarity with JavaScript and CSS to make good use of this document. See Also You may also find the following documents helpful: ● Safari DOM Additions Reference—describes the touch event classes that you use to handle multi-touch gestures in JavaScript. ● Safari CSS Reference—describes the CSS properties supported by various Safari and WebKit applications. ● Safari Web Content Guide—describes how to create content that is compatible with, optimized for, and customized for iOS. ● iOS Human Interface Guidelines—provides user interface guidelines for designing webpages and web applications for Safari on iOS. ● FingerTips—demonstrates how to build an interactive 3D carousel using CSS,JavaScript and touch events. ● http://dev.w3.org/csswg/css3-images/—W3C draft for gradients. ● http://www.w3.org/TR/css3-transitions/—W3C draft for animated transitions. ● http://www.w3.org/TR/css3-animations/—W3C draft for keyframe animations. ● http://www.w3.org/TR/css3-2d-transforms/—W3C draft for 2D transforms. ● http://www.w3.org/TR/css3-3d-transforms/—W3C draft for 3D transforms. Introduction Prerequisites 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 11Use gradients as color fills that blend smoothly from one color to another. Use a CSS gradient anywhere that you can use an image, such as for the background of an element, an element border, or a mask. Because gradients are resolution-independent and compact, a line or two of CSS can replace hundreds of kilobytes—or even megabytes—of graphic imagery. Unlike graphic images, gradients have no inherentsize, and automatically expand to fill a container. To create a gradient, specify a starting color and an ending color, and optionally intermediate colors and a direction. Safari supports two types of CSS gradients: linear and radial. This chapter describes both types of gradients. Safari 5.1 on the desktop, and Safari on iOS 5.0, use the -webkit- prefix for specifying gradients, but otherwise conform to the 17 February 2011 working draft for CSS3 gradients: http://dev.w3.org/csswg/css3- images/. Note: Recent drafts of the W3C proposal have simplified the syntax. This chapter describesthe most recent implementation shipping in Safari. You should expect Safari’ssyntax for gradientsto continue to change as the W3C standard evolves. While new syntax is expected, the existing syntax—and prior syntax—should still work. The -webkit-linear-gradient and webkit-radial-gradient properties require iOS 5.0 or later, or Safari 5.1 or later on the desktop. If you need to support earlier releases of iOS or Safari, see “Prior Syntax (-webkit-gradient)” (page 26). Creating Linear Gradients A linear gradient defines a color change along a specified line. Each point on the line has a particular color. The width of the line, perpendicular to the direction of the line, extendsto the edges of the gradient’s container. You can use a linear gradient to fill any two-dimensional shape. By default, a linear gradient changes colors from top to bottom. For example: background: -webkit-linear-gradient(aqua, white) 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 12 Using Gradientsdefines a linear gradient that starts as aqua at the top of the element and ends as white at the bottom of the element. The gradient fills the element completely, as Figure 1-1 illustrates. Figure 1-1 Simple linear gradient If you specify intermediate colors between the starting and ending color, the gradient blends from color to color. For example: background: -webkit-linear-gradient(red, yellow, orange, green, blue, purple); defines a rainbow gradient as a background. Apply this style to a div element, and the element is drawn with a rainbow background, as Figure 1-2 illustrates. Figure 1-2 Rainbow gradient Setting the Direction of Change You can define a linear gradient with the color change going in any direction: from any edge or corner to its opposite edge or corner, or at any specified angle. To specify a direction from edge-to-edge or corner-to-corner, just specify the beginning edge or corner. For example: ● background: -webkit-linear-gradient(left, black, white); creates a horizontal gradient going from left to right. ● background: -webkit-linear-gradient(bottom right, black, white); Using Gradients Creating Linear Gradients 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 13creates a diagonal gradient from bottom right to top left. You can also specify color change direction by supplying an angle. Angles are given in degrees, with 0deg being straight up and proceeding counterclockwise-positive, so that 90deg is horizontal left and 180deg is straight down. For example: -webkit-linear-gradient(45deg, black, white) creates a gradient at a 45 degree angle up and to the left. Note: If you specify a gradient from corner to corner, the angle of the gradient changesif the parent element is resized and the shape of the element changes. Specify the direction in degrees to create a gradient with a fixed angle. Figure 1-3 shows a diagonal gradient starting at the bottom left corner. Figure 1-3 Diagonal gradients Setting the Rate of Change By default, the rate of color change for a gradient remains constant; if the gradient has three colors, the blend starts with the first color at 0% of the gradient length, reaches the second color at 50% of the gradient length, and reaches the third color at 100% of the gradient length. In other words, the first line of the gradient is the starting color, the middle line is the second color, and the last line is the third color. To modify this behavior, specify color stops. For example, the following snippet creates a gradient that changes gradually from white to cornflower blue over 90% of the gradient length then blends quickly from to black over the remaining 10%: -webkit-linear-gradient(left, white, cornflowerblue 90%, black) Using Gradients Creating Linear Gradients 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 14Figure 1-4 shows such a gradient. Figure 1-4 Setting color stop percentages Color stops can create some striking effects. For example, specify the same color at two consecutive stops to create a band of solid color, or specify two different colors at the same percentage point to create an abrupt change in color. Figure 1-5 shows the effect these kind of color stops create. background: -webkit-linear-gradient(left,black,blue 10%,blue 90%,black); background: -webkit-linear-gradient(left,white,blue 50%,purple 50%,white); Figure 1-5 Solid color band and abrupt color change Using Gradients Creating Linear Gradients 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 15Creating Gradient Fades Use RGBa colors in a gradient to soften or fade colors into the background by decreasing the alpha value of the gradient. For example, Listing 1-1 creates a div element with a white background that fadesto transparent. Two consecutive white color stops are used, so the div element’s background stays white for 50% of its width and then fades into the background of the element’s parent. Figure 1-6 shows the result. Listing 1-1 Linear fade rgba gradient

RGBa Gradient Fades

Figure 1-6 Linear gradient fade Using Gradients Creating Linear Gradients 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 16Creating Radial Gradients A radial gradient is a color fill that blends from one color to another with the color change proceeding radially, forming a disk clipped by the shape of the element. The disk can be a circle or an ellipse. Specify a starting and ending color, and optionally specify intermediate colors. The starting color begins at the center of the disk, and the color change proceeds outward until the ending color isreached, by default at the farthest corner of the element being filled. By default, a radial gradient is an ellipse the height and width of the element being filled, with the center of the ellipse at the center of the element being filled. For example, the following snippet creates a radial gradient that blends from white at the center of a div element to black at the element’s outer edges, as Figure 1-7 illustrates:
Figure 1-7 Simple radial gradient To create a circular gradient, pass in the circle parameter: -webkit-radial-gradient(circle, white, black). Using Gradients Creating Radial Gradients 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 17The circle parameter parameter causes the gradient to be circular, instead of an ellipse that conforms to the shape of the element, as Figure 1-8 illustrates: Figure 1-8 Circular gradient Note that the shape of an element clips a circular gradient just as it does an elliptical gradient. Moving the Center By default, the starting point of a radial gradient isthe center of the element you are filling. Change this behavior by specifying a different starting point, using horizontal or vertical offsets from the element’s top left corner. The following example creates a circular div element (a square div element with a 50% border radius), then fills it with a radial gradient whose center is offset down and to the right of the element’s upper-left corner by 30%, creating a 3D lighting effect, as Figure 1-9 illustrates:
Figure 1-9 3D lighting effect Notice that you specify the vertical and horizontal offsets are as a distance from the top and left edge of the element, and that you specify both offsets as part of a single comma-delimited parameter, separated by a space. If you specify only a single value, Safari treats it as a vertical offset. Changing the Ending Color Location By default, a gradient reaches its ending color at the corner of the element furthest from the specified center of the gradient. Modify this behavior by specifying closest-corner. For example: -webkit-radial-gradient(30% 10%, closest-corner, white, black) creates a radial gradient that begins 30% to the right and 10% below the upper-left corner of an element, and reaches its end color at the closest corner. If you specify both the circle and the closest-corner properties, passthem in the same comma-delimited parameter, separated by a space: -webkit-radial-gradient(30% 10%, circle closest-corner, white, black) Using Gradients Creating Radial Gradients 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 19When the gradient ends at the closest corner, the ending color fills the remainder of the element. Figure 1-10 shows examples of identical div elements filled with radial gradients offset 30% down and to the right of the upper-left corner. Elliptical gradients are on the left of the illustration and circular gradients are on the right. Closest-corner gradient fills are above and default gradient fills are below: Figure 1-10 Closest-corner gradient fills Adding Color Stops To create a multi-colored radial gradient, specify intermediate colors between the starting and ending color. For example, the following snippet creates a radial gradient that blends from white at the center to green half way out, to black at the outer edge, as Figure 1-11 illustrates:
Figure 1-11 Multicolor gradient By default, the rate of color change is constant, dividing the gradient into equal-size color blends. Modify this behavior by providing color stops that specify the distance from the gradient center to its edge for particular colors. For example, the following snippet creates a gradient that blends from white to red in just 20% of the gradient, then takes the remaining 80% to fade to black, as Figure 1-12 illustrates:
Figure 1-12 Red color stop at 20% Using Gradients Creating Radial Gradients 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 21Specify paired color stops of the same color to create bands of solid color, or specify pairs of color stops with different colors at the same percentage point to create abrupt color changes. The following snippet defines two radial gradients, one with two color stops of the same color and the other with two differently colored stops at the same percentage point. Figure 1-13 shows the result: background: -webkit-radial-gradient(white, red 10%, red 90%, black); background: -webkit-radial-gradient(white, yellow 20%, red 20%, black); Figure 1-13 Color band and abrupt color change using color stops Creating a Radial Fade If you use RGBa colors in your color stops, you can specify both the hue and transparency of the gradient at any point. This enables you to create a gradient that blends into the background of its parent element. For example, Listing 1-2 creates a spotlight effect by fading a div element’s background from white to transparent, allowing the parent div’s background to gradually show through. Figure 1-14 shows the result: Listing 1-2 Radial fade rgba gradient

Spotlight On: Gradients

Using RGBA Colors

A radial gradient using rgba colors can be used to create a spotlight effect.

Figure 1-14 Spotlight gradient Creating Repeating Gradients You can create a repeating pattern in a gradient in two different ways. One way isto specify a series of repeating color stops. For example, the following snippet creates linear and radial gradients with two repeating red-to-blue-to-red blend stripes: -webkit-linear-gradient(red, blue 25%, red 50%, blue 75%, red) -webkit-radial-gradient(red, blue 25%, red 50%, blue 75%, red) It’s tedious to specify the color stops repeatedly when there are many repetitions, particularly if you need to calculate cumulative percentages for each color stop. To simplify the process, use the repeating gradient properties: -webkit-repeating-linear-gradient and -webkit-repeating-radial-gradient. To create a repeating gradient, specify the first set of color stops with percentages; the gradient repeats the pattern of colorstops, keeping the percentages proportional, as needed to reach 100%. The syntax for repeating Using Gradients Creating Repeating Gradients 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 23gradients is otherwise identical to nonrepeating gradients. The following snippet specifies color stops that fill 20% of two gradients, which createslinear and radial gradients with five repeating plum-to-powderblue-to-plum blend stripes, as Figure 1-15 illustrates. -webkit-repeating-linear-gradient(plum, powderblue 10%, plum 20%) -webkit-repeating-radial-gradient(plum, powderblue 10%, plum 20%) Figure 1-15 Repeating gradient patterns Note that the color pattern repeats from the starting color, so if the last color specified is the same as the starting color, the pattern repeats smoothly. If you specify a pattern whose last entry is different from the first entry, the color changes abruptly from the last color to the first color when the pattern repeats, instead of blending smoothly. Using a Gradient as a Border Image You can use a gradient anywhere you can use an image—as you would expect, this means you can use a gradient as a border image. However, the syntax is nonobvious. The border-image property uses four values to specify offsets for slicing the image into the top, bottom, and sides of the border. Since a gradient has no inherent size, a pixel or percentage offset into the image is meaningless; the only useful value is 100%. To make tiles from a linear gradient so that the border edges have the same color everywhere the tiles meet, start and end the gradient with the same color. For example, the following snippet creates a border like the one that Figure 1-16 shows.
Figure 1-16 Linear gradient border Radial gradients work nicely as borders, because the outer edges of all the tiles typically match when the stretch value is used for the repeat parameter. Here is an example of a radial gradient used as a border image:
Using Gradients Using a Gradient as a Border Image 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 25Figure 1-17 shows the result. Figure 1-17 Radial gradient border Prior Syntax (-webkit-gradient) The -webkit-linear-gradient and -webkit-radial-gradient properties are supported in iOS 5.0 and later, and in Safari 5.1 and later on the desktop. In prior versions of Safari, both linear and radial gradients were implemented using the -webkit-gradient property. If you need to support earlier versions of iOS or Safari, use the -webkit-gradient property to create gradients. The syntax is as follows: Specify linear gradients using the keyword linear, followed by a starting point, an ending point, a starting color with the keyword from, any color stops, and an ending color with the keyword to. ● Linear gradient, vertical from top: -webkit-gradient(linear, center top, center bottom, from(white), to(black)) ● Linear gradient, horizontal from left: -webkit-gradient(linear, center left, center right, from(white), to(black)) ● Linear gradient, diagonal from upper left: -webkit-gradient(linear, upper left, lower right, from(white), to(black)) ● Linear gradient, rainbow: Using Gradients Prior Syntax (-webkit-gradient) 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 26-webkit-gradient(linear, center left, center right, from(yellow), color-stop(20%, orange), color-stop(40%, red), color-stop(60%, green), color-stop(80%, blue), to(purple)) Specify radial gradients using the keyword radial, followed by a starting point, a starting radius, an ending point, an ending radius, a starting color, any color stops, and an ending color. ● Radial gradient, centered: -webkit-gradient(radial, center center, 0px, center center, 100%, from(white), to(black)) ● Radial gradient, offset: -webkit-gradient(radial, 20% 20%, 0px, 20% 20%, 60px, from(white), to(black)) ● Radial gradient, rainbow: -webkit-gradient(radial, center center, 0px, center center, 100%, from(yellow), color-stop(20%, orange), color-stop(40%, red), color-stop(60%, green), color-stop(80%, blue), to(purple)) The beginning radius specifies the size of the disk at the center of the gradient. The ending radius specifies the size of the disk at the end of the gradient. The gradient is circular if the beginning and ending center points are the same, elliptical otherwise. The gradient is clipped by the shape of the containing element if the ending radius specifies a larger disk than the element can contain. Using Gradients Prior Syntax (-webkit-gradient) 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 27A mask is a two-dimensional shape that acts as an overlay on an element and clips the element visually or renders portions of the element transparent or translucent. A mask consists of an image or a gradient that contains an alpha channel; where the alpha value of the mask is 0, the underlying element is transparent, or masked out; where the alpha value is 1, the underlying element displays normally; where the alpha value is between 0 and 1, the underlying element is proportionally transparent. Only the alpha values of the mask are used; any other color values are ignored. An element’s mask applies to its children and their descendants. The children and descendants may also have masks, in which case the masks are stacked. The transparent areas of a masked element reveal the underlying webpage contents, which may also contain masked elements; these masks too are stacked. The final image is rendered after concatenating all the masks in the stack, tiling and stretching them as specified. When a mask is applied to an element, both the contents and background of the element are masked. A mask may be applied to the entire element or it may exclude either the border or the combined border and padding. Using an Image as a Mask To apply a mask using an image, first create a .png or .svg image that contains an alpha channel. Pass the URL of thisimage into either the -webkit-mask-image property or the -webkit-mask-box-image property. The -webkit-mask-image property usesthe native size of the mask image. The -webkit-mask-box-image property scales the mask image to meet the edges of the element. If the image used as a mask consists of an opaque shape on a transparent background, the mask acts as a “cookie cutter” to clip an element in the shape of the mask. For example, the following snippet applies a heart-shaped mask to an image. Figure 2-1 shows the result. 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 28 Using Masks Figure 2-1 Heart-shaped “cookie-cutter” The -webkit-mask-box-image property takes optional arguments that work like the -webkit-border-image parameters. You can specify offsets into the mask image to slice it into top, right, bottom, and left images, applying the mask slices, stretched or repeated, to the edges of an element. For example, the following snippet uses a 50-pixel heart-shaped mask and adds a 50-pixel border to the image. The snippet also adds parameters to the -webkit-mask-box-image property, setting the slice size to the whole mask image and specifying repeat both horizontally and vertically. Figure 2-2 shows the result. Figure 2-2 Masking a border As mentioned previously, you can mask any HTML element, and you can concatenate masks by inheritance and by stacking masked elements. For example, Listing 2-1 creates a pair of masked div elements, each of which contains a paragraph element. The example positions the second div element so that it partly overlaps the first div element. The paragraph elements are masked by their parent div elements, and the two masks are stacked. The result is shown in Figure 2-3. Listing 2-1 Stacking masked elements stacked masks

This div element has a heart-shaped mask.This div element has a heart-shaped mask.This div element has a heart-shaped mask.This div element has a heart-shaped mask.This div element Using Masks Using an Image as a Mask 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 30has a heart-shaped mask.This div element has a heart-shaped mask.This div element has a heartshaped mask.This div element has a heart-shaped mask.

This div element has a heart-shaped mask.This div element has a heart-shaped mask.This div element has a heart-shaped mask.This div element has a heart-shaped mask.This div element has a heart-shaped mask.This div element has a heart-shaped mask.This div element has a heartshaped mask.This div element has a heart-shaped mask.

Figure 2-3 Stacking masks Using Masks Using an Image as a Mask 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 31You can use a mask to fade an element gradually into the background by including semitransparent pixels in the mask. For example, the following snippet applies a mask image with a solid center and increasingly transparent edges to the image of a field. The -webkit-mask-box-image property is used, so the mask is scaled to fit the img element. The result is shown in Figure 2-4. Figure 2-4 Applying a mask with a fuzzy border Image Mask Result Using a Gradient as a Mask Because gradients can be used in place of any image, a gradient can be passed as a mask. The following snippet defines a gradient that goes from opaque to transparent as a mask for an img element. The result is shown in Figure 2-5. Figure 2-5 Result of applying a gradient mask Note: The gradient in the example uses black asthe opaque color, but any completely opaque color would be equivalent. The example just given goesfrom opaque to transparent over the height of the image, but you can use different gradient parameters to achieve different effects. The following snippet creates a gradient from left to right and uses color stops to fade an image sharply at the edges, as shown in Figure 2-6. Notice that the image’s border radius works in concert with the mask. Figure 2-6 Horizontal gradient mask with color stops You can apply a gradient mask to any HTML element, not just images. For example, the following snippet creates a radial gradient as a mask for a div element containing several paragraphs of text. The result is shown in Figure 2-7.
Figure 2-7 Masking text with a radial gradient For more about gradients, see “Using Gradients” (page 12). Working with WebKit Mask Properties You can use either the -webkit-mask-image or the -webkit-mask-box-image property to assign a mask to an element. The -webkit-mask-box-image property scales the mask to fit the element by default, while the -webkit-mask-image property uses the mask image’s native size. Note: Gradients do not have a native size, so when using a gradient as a mask, the mask is always scaled to fit the mask bounding area (by default, the same as the masked element’s bounding area). The -webkit-mask-box-image property accepts optional parameters that enable it to act like a border image (for details, see Figure 2-5 (page 33)). There is also a set of propertiesthat you can use to modify the behavior of the -webkit-mask-image property, including: ● -webkit-mask-clip—Causes the mask to apply to the whole element, only the padding and content, or only the content. Set to border-box (default), padding-box, or content-box. Using Masks Working with WebKit Mask Properties 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 35● -webkit-mask-origin—Sets the origin of the mask to the upper left corner of the element’s border, padding, or content box. Set to border (default), padding, or content. ● -webkit-mask-position—Anchors the upper-left corner of the mask at the specified offset from the origin. Accepts an x-offset and a y-offset. ● -webkit-mask-repeat—Controls how the mask is tiled to cover the element. Accepts an x-repeat and a y-repeat parameter. Both parameters can be set to repeat, space, round, or no-repeat. The specifics are the same asfor the background-repeat property (see http://www.w3.org/TR/css3-background/#thebackground-repeat). ● -webkit-mask-size—Controls how the mask is sized to cover the element. The specifics are the same as for the background-size property (see http://www.w3.org/TR/css3-background/#the-backgroundsize). The properties that apply to webkit-mask-image are analogous to the CSS3 background properties. See http://www.w3.org/TR/css3-background/#backgrounds for details. Using Masks Working with WebKit Mask Properties 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 36A reflection is a mirror image, optionally with its own mask. You can add a reflection to any visible HTML element. Reflections update automatically as the element’s appearance changes. If you hover over a link with a reflection, for example, you see the hover effect in the reflection. If you add a reflection to a video element, the video plays in the reflection as well. Resize the element and the reflection is resized. Reflections are not interactive elements, however—clicking or touching a reflection does not generate any events. Reflections have no effect on layout other than being part of a container’s overflow, and are similar to box shadows in this respect. In other words, you must position elements explicitly to allow space for reflections; if you add a reflection below an image, and follow the image with a paragraph of text, the reflection may cover the text (depending on the size of the image, padding, margins, and so on). Adding a Reflection Use the -webkit-box-reflect property to add a reflection to an element. The first, mandatory, parameter is the direction in which the reflection projects, which can be above, below, left, or right. For example, the following snippet adds a reflection below an h1 element, as Figure 3-1 illustrates:

Reflection in Blue 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 37 Using Reflections

Figure 3-1 Reflection below a heading The reflection is the same visible size as the element. The element border and padding are included in the reflection. Adjusting the Reflection’s Position The first argument of the -webkit-box-reflect property specifiesthe direction of the reflection. An optional second argument specifies the offset or space between the original image and the reflection. By default, the reflection begins with no separation from the element’s bounding box. To change this behavior, add an offset parameter. A positive offset causes the reflection to be separated from the element by additional space; a negative offset causes the reflection to overlap the element. For example, the bounding box of an h1 element includes substantial white space; to tuck the reflection in closer to the text, add a negative offset. The following example adds an offset of -15px to the reflection. The result is shown in Figure 3-1: Using Reflections Adjusting the Reflection’s Position 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 38

Figure 3-2 Reflection with negative offset Masking a Reflection An optional third argument to -webkit-box-reflect specifies a mask to apply to the reflection. A mask renders part of the reflection transparent or translucent. The mask is either an image file, specified as a URL, or a gradient. A mask image file can be a .png, an .svg, or a .gif with transparent areas. The alpha value of the mask is applied to the reflection on a pixel-by-pixel basis. Only the alpha value of the mask’s color values has any effect on the reflection. When creating a mask, shape it to mask the target element itself, not to mask the reflection. The reflection shows a mirror image of the masked element, even though the element does not appear masked. The following snippet adds a mask image to a reflection. Figure 3-3 shows the resulting masked reflection side-by-side with the mask image. Using Reflections Masking a Reflection 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 39style="-webkit-box-reflect: below 0px url(mask.png);" Figure 3-3 Reflection with image as mask The following snippet adds a reflection below an image, using a gradient as a mask. Figure 3-4 shows the result. Figure 3-4 Image with reflection and gradient mask Note that the reflection includes the rounded borders of the img element. Notice also that the gradient goes from transparent at the top to opaque at the bottom—the opposite of its appearance in the reflection; this is because the reflection shows a mirror image of the masked element. For more about masks, see “Using Masks” (page 28); for more about gradients, see “Using Gradients” (page 12). Inner Reflections When you reflect an element, all of the element’s descendants are displayed in the reflection. If you add a reflection to a child element, the child’sreflection isrendered first; thisinner reflection isincluded in the parent element’s reflection. The following snippet adds a reflection to a div element containing an img element that has its own reflection. Figure 3-5 shows the result:
Using Reflections Inner Reflections 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 41

Text...

Text...

Figure 3-5 Inner reflection, reflected Using Reflections Inner Reflections 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 42Safari 6 and later supports CSS filters, or special visual effects, that you can apply to many elements, including videos (see Figure 4-1 (page 43)). These hardware-accelerated filters (such as brightness, contrast, saturation, and blur) can be stacked on top of and animated against one another. Read “CSS Property Functions” in Safari CSS Reference to find out more about CSS filters. Figure 4-1 CSS filters on a video Using CSS Filters To add a CSS filter to an HTML element, include the -webkit-filter property in the element’s CSS declaration, as shown in Listing 4-1 (page 44). You can list as many of the functions found in “CSS Property Functions” in Safari CSS Reference as you’d like. 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 43 Using CSS FiltersListing 4-1 Applying CSS filters to HTML elements Filters

Video with and without CSS filters

The video on the left does not have CSS filters applied, while the video on the right does.

These videos are playing from the same source file.

Using CSS Filters 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 44You can create animations entirely in CSS, with no need for plug-ins, graphics libraries, or elaborate JavaScript programs. Normally, when the value of a CSS property changes, the affected elements are re-rendered immediately using the new property value. If you set CSS transition properties, however, any changes in the values of the specified CSS properties are automatically rendered as animations. This kind of automatic animation is called a transition. You trigger a transition simply by changing any of the specified CSS values. CSS property values can be changed by a pseudoclass, such as :hover, or by using JavaScript to change an element’s class name or to change its individual CSS properties explicitly. The animation flows smoothly from the original state to the changed state using a transition timing function over a specified duration. For more complex animationsthat can use arbitrary intermediate states and trigger conditions,see “Animating With Keyframes” (page 50). Transitions are especially powerful if you combine them with 2D and 3D transforms. For example, Figure 5-1 shows the results of applying an animated transition to an element as it rotates in 3D. See the CardFlip sample code project for the complete source code for this example. Figure 5-1 Card Flip example See the HTML version of this document to view the video. document to view the video. Animated transitions are a W3C draft specification: http://www.w3.org/TR/css3-transitions/. 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 45 Animating CSS TransitionsNote: Not all CSS properties are animatable. In general, any CSS property that accepts values that are numbers, lengths, percentages, or colorsis animatable. Some CSS propertiesthat accept discrete values can be animated as well, but display a jump between values rather than a smooth transition when changed, such as the visibility property. See Safari CSS Reference for which properties are animatable. Setting Transition Properties To create an animated transition, first specify which CSS properties should be animated, using the -webkit-transition-property property, a CSS property that takes other CSS properties as arguments. Set the duration of the animation using the -webkit-transition-duration property. For example, Listing 5-1 creates a div element that fades out slowly over 2 seconds when clicked. Listing 5-1 Setting transition properties

Click me and I fade away. . .

There are two special transition properties: all and none: ● -webkit-transition-property: all; ● -webkit-transition-property: none; Setting the transition property to all causes all changes in CSS properties to be animated for that element. Setting the transition property to none cancels transition animation effects for that element. To set up an animation for multiple properties, pass multiple comma-separated parameters to -webkit-transition-property and -webkit-transition-duration. The order of the parameters determines which transition the settings apply to. For example, Listing 5-2 defines a two-second -background-color transition and a four-second opacity transition. Animating CSS Transitions Setting Transition Properties 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 46Listing 5-2 Creating multiple transitions at once div.zoom-fade { -webkit-transition-property: background-color, opacity; -webkit-transition-duration: 2s, 4s; } Using Timing Functions Timing functions allow a transition to change speed over its duration. Set a timing function using the -webkit-transition-timing-function property. Choose one of the prebuilt timing functions—ease, ease-in, ease-out, or ease-in-out—or specify cubic-bezier and pass in control parameters to create your own timing function. For example, the following snippet defines a 1-second transition when opacity changes, using the ease-in timing function, which starts slowly and then speeds up: style="-webkit-transition-property: opacity; -webkit-transition-duration: 1s; -webkit-timing-function: ease-in;" Using the cubic-bezier timing function, you can, for example, define a timing function thatstarts outslowly, speeds up, and slows down at the end. The timing function is specified using a cubic Bezier curve, which is defined by four control points, as Figure 5-2 illustrates. The first and last control points are always set to (0,0) and (1,1), so you specify the two in-between control points. The points are specified using x,y coordinates, with x expressed as a fraction of the overall duration and y expressed as a fraction of the overall change. Figure 5-2 Cubic Bezier timing function Fraction of elapsed time Fraction of change 0, 0 1.0,1.0 0.9, 0.4 0.5, 0.2 0.5 0.0 1.0 0.0 0.5 1.0 Animating CSS Transitions Using Timing Functions 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 47For example, Listing 5-3 creates a 2-second animation when the opacity property changes, using a custom Bezier path. Listing 5-3 Defining a custom timing function div.zoom-fade { -webkit-transition-property: opacity; -webkit-transition-duration: 2s; -webkit-transition-timing-function: cubic-bezier(0.5, 0.2, 0.9, 0.4); } In the example just given, the custom timing function starts very slowly, completing only 20% of the change after 50% of the duration, and 40% of the change after 90% of the duration. The animation then finishesswiftly, completing the remaining 60% of the change in the remaining 10% of the duration. Delaying the Start By default, a transition animation begins as soon as one of the specified CSS properties changes. To specify a delay between the time a transition property is changed and the time the animation begins, use the -webkit-transition-delay property. For example, the following snippet defines an animation that beings 100ms after a property changes: .delay-fade { -webkit-transition-property: opacity; -webkit-transition-duration: 1s; -webkit-transition-delay: 100ms; } Setting Several Transition Properties At Once You can set an animation’s transition properties, duration, timing function, and delay using a single shorthand property: -webkit-transition. For example, the following snippet uses the :HOVER pseudostyle to cause img elements to fade in and out when hovered over, using a one-second animation that begins 100 ms after the hover begins or ends, and using the ease-out timing function: Handling Intermediate States and Events When applying a transition to an element’s property, the change animates smoothly from the old value to the new value and the property values are recomputed over time. Consequently, getting the value of a property during a transition may return an intermediate value that is the current animated value, not the old or new value. For example, suppose you define a transition for the left and background-color properties and then set both property values of an element at the same time. The element’s old position and color transition to the new position and color over time as illustrated in Figure 5-3. Querying the properties in the middle of the transition returns an intermediate location and color for the element. Figure 5-3 Transition of two properties Starting appearance Time = 0.0 sec Intermediate appearance Time = 0.5 sec Final appearance Time = 1.0 sec To determine when a transition completes, set a JavaScript event listener function for the DOM event that is sent at the end of a transition. The event is an instance of WebKitTransitionEvent, and its type is webkitTransitionEnd. For example, the snippet in Listing 5-4 displays an alert panel whenever a transition ends. Listing 5-4 Detecting transition end events document.body.addEventListener( 'webkitTransitionEnd', function(event) { alert( "Finished transition!" ); }, false ); Animating CSS Transitions Handling Intermediate States and Events 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 49Safarisupportstwo types of CSS animation: transition animations and keyframe animations. To simply animate changesin CSS properties whenever those properties change, you should probably use an animated transition (see “Animating CSS Transitions” (page 45)). To create complex animations—such as a bumblebee’s flight or a change that starts and stops or repeats indefinitely—or to trigger animations under arbitrary conditions using JavaScript, use keyframe animations. Keyframe animations include the following features: ● Choose any number of CSS properties to change and define points along a timeline that have specific states. ● Animation between two defined points is automatic but can be guided by specifying a timing function. ● You trigger keyframe animations explicitly. ● Keyframe animations can be set to repeat a finite number of times or to repeat indefinitely, proceeding in the same direction each time, or alternating forward and backward. ● Keyframe animations can be paused and resumed. ● All of the elements in a class can be animated as part of a single animation. When a keyframe animation completes, an animated element returns to its original CSS style. You can override this behavior, however, and make the final animation state persistent. You can also change an element’s style when the animation ends by installing a JavaScript listener function for the webkitAnimationEnd event. Create stunning effects by combining animation with 2D and 3D transforms. For example, Figure 6-1 shows an animation of text elements in 3D space. See the PosterCircle sample code project for the complete source code for this example. Figure 6-1 Animated text elements See the HTML version of this document to view the video. document to view the video. 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 50 Animating With KeyframesKeyframe animation is a W3C draft. See http://dev.w3.org/csswg/css3-animations/. Creating a Keyframe Animation A keyframe animation has—at minimum—a name, a duration, and one or more keyframes. A keyframe is a CSS rule consisting of a set of properties and values associated with a point in time. To create a keyframe animation, perform the following steps: 1. Create a named set of keyframes in CSS using the @-webkit-keyframes rule. The set must include at least one keyframe. 2. Set the -webkit-animation-duration property to a positive, nonzero value. 3. Set the -webkit-animation-name property to the name of the set of keyframes. The following example defines a single keyframe in a set named glow. The keyframe specifies a blue background color. The example definesthe div:hover pseudoclass as having the animation name glow and the animation duration of 1s. When the user hovers over or touches any div element, it turns blue for one second. Listing 6-1 Simple keyframe animation Blue Glow

Hover turns me briefly blue.

Animating With Keyframes Creating a Keyframe Animation 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 51

Me too.

animated div

Click to slide right and down, then back.

Controlling Animation Using JavaScript Control a CSS animation using JavaScript either by changing an element’s className property or by changing an element’s animation style properties individually. One thing to remember is that the JavaScript name for a property is not always the same as the CSS name. Compound names in CSS typically contain dashes, but in Animating With Keyframes Controlling Animation Using JavaScript 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 56JavaScript the dash is the subtraction operator, so JavaScript names omit the dash. Compound names in JavaScript usually capitalize the first character of each word after the first word; so if a CSS name were -extension-foo-bar, the JavaScript name would usually be extensionFooBar. As an example, to set the CSS property -webkit-animation-play-state from JavaScript,set the element’s style.webkitAnimationPlayState property. Listing 6-4 creates three buttons and a round div element with a radial gradient background. The first button animates the div element by changing its class name. The second and third buttons pause and continue the animation by setting the div element’s style.webkitAnimationPlayState property. Figure 6-3 illustrates the result. Listing 6-4 Pausing and continuing an animation bouncing div Animating With Keyframes Controlling Animation Using JavaScript 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 57

 

Figure 6-3 JavaScript control of animation Handling Animation Events Three animation-related events are available through the DOM event system: Animating With Keyframes Handling Animation Events 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 58● webkitAnimationStart—Sent when the animation begins (after any specified delay). ● webkitAnimationIteration—Sent at the end of each iteration. ● webkitAnimationEnd—Sent after the final iteration. Note that when the final iteration in a series completes, it triggers both a webkitAnimationIteration and a webkitAnimationEnd event. Each of these events has three significant properties: ● The event.target property is the object being animated. ● The event.animationName property is the name of the animation that generated the event. ● The event.elapsedTime property is the length of time the animation has been running. Elapsed time does not include any time the animation was in the paused play state, nor does it include any specified delay time. As an example of event handling, Listing 6-5 creates three colored balls (round div elements) that roll away and disappear when clicked. The balls are given a class name that includes animation but begins with the animation play state set to paused; an onclick handler in each ball sets the play state for that element to running. The example adds an event listener for webkitAnimationEnd events on the body element. When a webkitAnimationEnd event occurs, the listener function removes the animated element by changing the element’s style.display property to none. Listing 6-5 Handling animation events rolling divs Click the colored balls to make them roll away:
Note: To see the example in action, copy the listing into a text editor and save it with the .html file extension. Animating With Keyframes Handling Animation Events 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 60Use CSS transform propertiesto give webpages a rich visual appearance without needing image files. Elements can be positioned, rotated, and scaled in 2D and 3D space; perspective can also be applied, giving elements the appearance of depth. For example, Figure 7-1 shows a simple HTML document, containing only div elements and text but rendered using CSS transform and gradient properties. It appears to be a graphics-intensive page, yet the actual content is less than 2 KB of text, and the elements animate smoothly in 3D under user control. Figure 7-1 HTML page with rotation and perspective transforms 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 61 Using 2D and 3D TransformsHow does this work? HTML elements are, after all, inherently two-dimensional, or planar; they have height and width, but no thickness. By rotating planar elements into the third dimension and applying perspective, however, these elements can be combined to create apparently solid objects. For example, five div elements are combined in Figure 7-1 to form the sides and bottom of an open box; the ball inside the box is another div element with rounded borders—a radial gradient gives it the appearance of depth. Safari uses a series of transformation matrices to determine the mapping of every pixel on the screen. You don’t need to understand matrices to use them, however. You can apply a transform either by using a matrix or by calling one of the transform functions, such as scale() or rotate(). Transforming an element typically causes its image to be rendered in a different position on the screen, but the position and dimensions of the element on the page are not changed—the top, left, height, and width properties, for example, are not altered by transforms. It isthe coordinate system in which the element is drawn that is changed. Consequently, changing transform properties does not affect the layout of a webpage. This means that transforming an element can cause it to visually overlap neighboring elements, even though their positions and dimensions on the page may not overlap. Note: Mouse and touch events, such as onclick, track the visual representation of an element, taking 2D and 3D transforms into account. By default, transforms are applied using the center point of an element as the origin; rotation spins an object about its center, for example, and scaling expands or contracts an element from the center point. You can change the origin by setting the -webkit-transform-origin property. A transform can cause part of an element to be displayed in the element’s overflow area. If the value of the overflow property is scroll or auto, scroll bars appear as needed if a transform renders part of an object outside the display area. Safari supports both 2D and 3D transforms. Both 2D and 3D transforms are W3C drafts. See http://www.w3.org/TR/css3-2d-transforms/ and http://www.w3.org/TR/css3-3d-transforms/ for the specifications. 2D Transform Functions To apply a 2D transform to an element, use the -webkit-transform property. The transform property can be set using predefined transform functions—translation, rotation, and scaling—or it can be set using a matrix. Using 2D and 3D Transforms 2D Transform Functions 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 622D Translation 2D translation shifts the contents of an element by a horizontal or vertical offset without changing the top or left properties. The element’s position in the page layout is not changed, but the content is shifted and a shifted coordinate system applies to all descendants of the translated element. For example, if a div element is positioned at the point 10,10 using the CSS properties top and left, and the element is then translated 100 pixels to the right, the element’s content is drawn at 110,10. If a child of that div is positioned absolutely at the point 0,100, the child is also shifted to the right and is drawn at the point 110,110; the specified position of 0,100 is shifted right by 100, and the child is drawn at 100,100 relative to the parent’s upper-left corner, which is still at 10,10. Figure 7-2 illustrates this example. Figure 7-2 A translated element and its offspring To apply a 2D translation, set the -webkit-transform property to translateX(offset), translateY(offset), or both. For example:
2D Rotation 2D rotation is a rotation in the xy plane. By default, 2D rotation spins an object around its center point. To rotate an element around a different point,see “Changing the Origin” (page 67). Rotation isspecified in degrees clockwise from the element’s orientation after any inherited rotation; rotation affects the specified element and all of its descendants. The coordinate system of any descendants is likewise rotated. Using 2D and 3D Transforms 2D Transform Functions 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 63The following snippet rotates a div element 45 degrees clockwise, as shown in Figure 7-3. The div element has a beige background and contains a paragraph of text and an image; both the text and the image inherit the div element’s rotation. A second div is positioned under the rotated div to show the original div’s position prior to rotation.
Figure 7-3 Rotating an element Rotation can be specified in positive or negative degrees. For example, -webkit-transform: rotate(-45deg); specifies a 45 degree rotation counterclockwise. If rotation is animated,specifying a degree of rotation greater than the current degree causes clockwise rotation; specifying a degree of rotation less than the current degree causes counter-clockwise rotation. When animating rotation, it can be useful to specify a rotation of more than 360 degrees. For example, Listing 7-1 uses JavaScript to set a rotation of 3600deg, causing a div element to spin clockwise ten times. The text spins once on page load, and a button lets the user spin it again. Listing 7-1 Animating 2D rotation spin-in text

Spinning text!

Whew! I'm dizzy...
Notice that the CSS property -webkit-transform is addressed in JavaScript as element.style.webkitTransform. Notice also that the spin() function increments the rotation angle by 3600 each time it is called; setting the angle to 3600deg repeatedly would have no effect. 2D Scaling 2D scaling makes an element smaller or larger in one or two dimensions. Scaling affects the whole element, including any border thickness. By default, the element isscaled up or down relative to its center, which causes all four of the element’s corners to be redrawn at new locations. The element’s top, left, height, and width properties are unchanged, however,so the layout of the page is not affected. Consequently,scaling an element up can cause it to cover other elements on the page unless you design the layout to allow room for the expansion. Using 2D and 3D Transforms 2D Transform Functions 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 65Scaling modifies the coordinate system of an element’s descendants, multiplying the x and y values by the specified scaling factor. For example, if a div element contains an image positioned absolutely at 10,10, with a height and width of 100 pixels, scaling-up the div element by a factor of two results in a 200 x 200 image, positioned at 20,20 relative to the div’s upper-left corner, which moves up and to the left. Figure 7-4 illustrates this behavior. Figure 7-4 Scaling an element up Apply a scale transformation by setting the -webkit-transform property to scale(x y), where x and y are independent scale factors for width and height, or by setting the transform property to scale(size), where size is the scaling factor in both dimensions. For example: style="webkit-transform: scale(1, 2)" renders an element the same width, but twice as tall. style="webkit-transform: scale(2, 0.5)" renders an element twice as wide and half as tall. style="webkit-transform: scale(1.5)" renders an element 1.5 times larger. Setting Multiple Transforms Different transforms, such as rotation and scaling, are applied by setting different values to a single property: -webkit-transform. Consequently, if you apply one transform to an element and then specify another transform, the first transform is no longer applied; the new value overwrites the old one, as with any CSS property. There are two different ways to perform multiple transforms on an element—both scaling and rotating an element for example: Using 2D and 3D Transforms Setting Multiple Transforms 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 66● Use inheritance to apply multiple transforms: create a scaled div element, for example, add your element as a child, then rotate the child element. ● Set the -webkit-transform property of the element to a space-delimited list of transform functions, such as: -webkit-transform: scale(2) rotate(45deg); When a list of functionsis provided, the final transformation value for the element is obtained by performing a matrix concatenation of each entry in the list. (Matrix concatenation can have some side effects, such as normalizing the rotation angle modulo 360.) Both approaches—transform inheritance and transform function lists—are valid. The following two examples illustrate two ways to apply a set of transforms to an element. Listing 7-2 sets an element’s transform property to a list of transform functions. Listing 7-3 produces the same results by applying each transform to a nested element. Listing 7-2 Setting multiple transforms using a list
Listing 7-3 Nesting 2D transforms
Changing the Origin By default, the origin for transforms is the center of an element’s bounding box. Most HTML and CSS entities use the upper-left corner as the default origin, but for transforms, it is usually more convenient to use the center of an element as a reference point. Consequently, elements rotate around their center by default, and scale up or down from the center out. Using 2D and 3D Transforms Changing the Origin 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 67To change the origin for transforms of a given element, set the -webkit-transform-origin property. The new origin is specified as a distance or percentage from the element’s upper-left corner. For example, the default center origin can be expressed as -webkit-transform-origin: 50% 50%;. Changing the origin to 0% 0% or 0px 0px causes transformation to occur around the upper-left corner of the element. The code in Listing 7-4 rotates the second box in Figure 7-5 around the top-right corner. Listing 7-4 Rotating an element around the top-right corner

I am rotated about my top-right corner.

Figure 7-5 Element rotated around the top-right corner Using 2D and 3D Transforms Changing the Origin 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 683D Transforms The standard HTML coordinate system has two axes—the x-axis increases horizontally to the right, and the y-axis increases vertically downwards. With 3D transforms, a z-axis is added, with positive values rising out of the window toward the user and negative values falling away from the user, as Figure 7-6 illustrates. Figure 7-6 3D coordinate space – Z - Y + Y + X – X + Z 3D transforms move an element out of the usual xy plane, where z=0—the plane of the display. A transformed element isstill two dimensional, but it no longer liesin the usual plane. A transformed object may be translated along the z-axis, rotated around the x- or y-axis, or transformed using some combination of translation and rotation. All HTML elements have a z-index. The z-index controls the rendering order when elements overlap. An element’s z-index has nothing to do with its z-axis coordinate. Transformed objects follow the standard HTML rendering rules—objects with higher z-index values are drawn on top of other objects with lower z-index values—but for elements sharing the same z-index, the areas with higher z-axis coordinate values are drawn on top. Using 2D and 3D Transforms 3D Transforms 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 69Adding 3D Perspective To render elements with the appearance of depth, you must specify a perspective. If you apply 3D transforms without setting the perspective, elements appear flattened. For example, if you rotate an element around its y-axis without setting the perspective, the element just appears narrower. If you rotate an element 90 degrees from the default xy plane, it is seen edge-on—the element either disappears entirely or is displayed as a line. Adding perspective distorts the appearance of objects realistically, making nearby things appear larger and distant things look smaller. The closer the object, the greater the distortion. In order for Safari to create the illusion of depth, it’s necessary to specify a point of view, or perspective. Once Safari knows where the user’s eye is relative to an element, it knows how much distortion to apply and where. Use the -webkit-perspective property to set the perspective for all the descendants of an element. For example:
The perspective is specified in distance from the screen. You may specify the distance in pixels, centimeters, inches, or any CSS distance unit. If no unit type is supplied, px is assumed. Note: Perspective distortion can cause part or all of an element to be displayed offscreen, particularly if an object’s z-coordinates are positive and the projected image would extend beyond the specified viewpoint, somewhere behind the user’s eye. Tip: Perspective settings of 300px or less tend to create intense perspective distortion; settings from 500px to 1000px create moderate perspective distortion, and settings of more than 2000px give very mild perspective distortion. Listing 7-5 sets the -webkit-perspective property using a slider. Listing 7-5 Adding a perspective slider applying perspective

Left

Center

Right

The center element is edge-on, and not visible.

Using 2D and 3D Transforms 3D Transforms 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 73 Figure 7-8 Perspective origin effects Creating a 3D Space By default, the descendants of an element are flattened into the plane of their parent. When you apply a 3D transform to an element, that element’s plane is no longer the default xy plane—the plane of the display. All descendants of the element share that element’s new plane. In order to further transform the children of an element relative to that element’s plane, you must set the -webkit-transform-style property to preserve-3d, creating a 3D space. For example:
Setting the transform style to preserve-3d in an element makes that element into a 3D container; all the element’s immediate children can be manipulated independently in 3D, relative to the parent. Because HTML elements are flat, a transformed child also occupies a plane in 3D space. Each child can occupy a separate plane, or multiple children can share the same plane. By default, any descendants of these transformed children are flattened into their parental plane; setting the transform style to preserve-3d affects only an element’s immediate children. Using 2D and 3D Transforms 3D Transforms 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 743D containers can be nested. Enabling 3D transforms in one of a container element’s descendants creates a nested 3D layer; children of that descendant can be transformed in 3D, relative to their container’s plane. You need to enable 3D in a particular element only if the element’s children are to be transformed in 3D relative to that element’s plane. Any transform applied to a 3D container is inherited by all of its descendants. By applying a rotation to the highest level 3D container, for example, you are able to rotate the view of all of the container’s contents at once. Listing 7-7 gives an example of a nested pair of 3D containers, illustrated in Figure 7-9. The topmost container has a child div element rotated 45 degrees on its x-axis, so it appears to be tilted away from the viewer. This child div is also a 3D container, containing a paragraph of text rotated 35 degrees on its right edge away from the container, causing the text to appear to lift off the page. Listing 7-7 Nested 3D rotations

And so the text seems to lift off the page and float, as if transformed. Well, I suppose it is transformed, and that explains the appearance, if not quite the magic, of it...

Using 2D and 3D Transforms 3D Transforms 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 75 Figure 7-9 Text rotated relative to 3D backdrop Generally speaking, you need to create only a single 3D container—all 3D transforms can be applied relative to the default xy plane, and global transforms can be applied to the top-level container and inherited by all its descendants. Sometimesit may be convenient to manipulate a subgroup of transformed elements as a unit, however; in such a case, it makes sense to create a nested container. To disable 3D for an element’s children dynamically, set the -webkit-transform-style property to flat. Applying a 3D transform when the transform style is set to flat does not move the element out of its parent’s plane. Note: Elements that have overflow set to hidden are unable to render their child elements in 3D, and are rendered as though the transform style were set to flat. 3D Transform Functions Like 2D transforms, 3D transforms are set using the -webkit-transform property. You can apply a transform to an element by specifying a transform function, a list of transform functions, or by passing in a 3D matrix. There are several functions that perform 3D transforms: Using 2D and 3D Transforms 3D Transforms 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 76● translateZ(distance)—Moves an element closer or farther away. ● translate3d(x, y, z)—Moves an element in three dimensions. ● rotateX(degrees)—Rotates an element around the x-axis, moving the top and bottom closer or farther away. ● rotateY(degrees)—Rotates an element around the y-axis, moving the left and right sides closer or farther away. ● perspective(distance)—Sets the 3D perspective for a single element. Important: You must set a perspective for 3D transforms to have a visible 3D effect. See “Adding 3D Perspective” (page 70) and “Creating a 3D Space” (page 74) for details. 3D Translation 3D translation moves an element closer to or farther from the viewer by changing its position on the z-axis. Use the translateZ() function to shift an element on the z-axis, or the translate3d(x, y, z) function to shift an element on two or three axes. For example:
Using 2D and 3D Transforms 3D Transforms 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 77The 3D translation functions work like their 2D counterparts, except that the z offset cannot be specified as a percentage. Z-axis units may be positive (towards the viewer) or negative (away from the viewer). Figure 7-10 shows two identical div elements with same height, width, and x and y positions, one translated on the z-axis by 100 px and the other translated by -100 px. Figure 7-10 Z-axis translation in perspective All descendants of an element inherit its z-axis translation. Note that the text in the previous illustration is translated along with its parent. 3D Rotation You can rotate an element in 3D either around the y-axis,so that the right and left edges get nearer and farther away, or around the x-axis, so that the top and bottom edges get nearer and farther away. For example:
Using 2D and 3D Transforms 3D Transforms 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 78Rotation is around an imaginary x- or y-axis that passes through the element’s origin. By default, the origin is at the center of an object. Positive x units rotate the top edge away. Positive y units rotate the right edge away. This is illustrated in Figure 7-11. Figure 7-11 X and y rotation All descendants of an element inherit its 3D rotation. Note that the text in the previous illustration is rotated along with its parent. Setting Perspective for a Single Element To create a 3D space with a shared perspective, you need to create a 3D container that has the -webkit-perspective property set; but if you just want to render a single element with the appearance of depth, you can set the -webkit-transform property to a list of transform functions that includes the perspective(distance) function as the first transform. For example:

This text is rotated 45 degrees around its x-axis.

The foregoing snippet performs two 3D transforms on an element—rotation about the x-axis and perspective distortion, as if the user were viewing the object from 10 cm in front of the screen. Using 2D and 3D Transforms 3D Transforms 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 79Important: The perspective() transform function must be the first function in the list of transforms—you must establish the perspective prior to applying the other transforms. In almost all cases, it is better to create a 3D container and set the -webkit-perspective property for the container element than it isto apply the perspective() transform to an element directly. See Figure 7-7 (page 72) for details. Back Face Visibility If an element is rotated 90 degrees or more around the x- or y-axis, the back face of the element faces the user. The back face of an element is always transparent, so the user sees a reversed image of the front face through the transparent back face, like a sign painted on a glass door and seen from behind. To prevent the mirror image of the front face from being displayed, set the -webkit-backface-visibility property to hidden. For example: -webkit-backface-visibility: hidden; When -webkit-backface-visibility is set to hidden, an element is not displayed where its back face would be visible. One reason to do this is to create the illusion that an element has two faces, each with their own content. For example, to create the illusion of a card with different contents on the front and back face, two elements are positioned back to back in the same location. The two elements are then rotated together, progressively hiding the front element and revealing the back element. If the back face of the top element were visible, it would obscure the element beneath it instead of revealing the element beneath it as it rotates. Listing 7-8 creates the illusion of a card with content on both sides, as Figure 7-12 shows. Listing 7-8 Hiding the back side of a card flip card Using 2D and 3D Transforms Back Face Visibility 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 80
Back of card
Front of card
Figure 7-12 Cardflip example See the HTML version of this document to view the video. document to view the video. Using Transformation Matrices A transformation matrix is a small array of numbers (nine numbers for a 2D matrix, sixteen for a 3D matrix) used to transform another array, such as a bitmap, using linear algebra. Safari provides convenience functions for the most common matrix operations—translation, rotation, and scaling—but you can apply other transforms, such as reflection or shearing, by setting the matrix yourself. Using 2D and 3D Transforms Using Transformation Matrices 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 812D Matrix Operations For a 2D transform, set the -webkit-transform property to matrix(a,b,c,d,e,f), where the matrix position of the parametersisin column order, as Figure 7-13 shows. The first column in the matrix isthe x vector; the second column is the y vector. Figure 7-13 2D transformation matrix parameter positions c 0 0 1 b a d e f To make full use of transformation matrices, you need an understanding of linear algebra. But even without an understanding of linear algebra, you can often look up the matrix values for a particular effect. For example, here are the settings for reflection around the x- and y-axes: Reflection around the y-axis— -webkit-transform: matrix(-1,0,0,1,0,0); Reflection around the x-axis— -webkit-transform: matrix(1,0,0,-1,0,0); Here are the matrix parameter settings for some common effects: translate(x, y) = matrix(1, 0, 0, 1, x, y) scale(x, y) = matrix(x, 0, 0, y, 0, 0) rotate(a) = matrix(cos(a), sin(a), -sin(a), cos(a), 0, 0) skewx(a) = matrix(1, 0, tan(a), 1, 0, 0) skewy(a) = matrix(1, tan(a), 0, 1, 0, 0) An example of using matrix settingsto mirror,stretch, and skew elementsis given in Listing 7-9 and isillustrated in Figure 7-14. Listing 7-9 Matrix example Mirror transform
This element is reflected.
This element is reflected.
This element is reflected and stretched.
This element is reflected and stretched.
This element is reflected, stretched, and skewed.
This element is reflected, stretched, and skewed.
Figure 7-14 Matrix mirroring transforms Using 2D and 3D Transforms Using Transformation Matrices 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 833D Matrix Operations For a 3D transform, set the -webkit-transform property to matrix3d(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p), where the parameters are a homogeneous 4 x 4 matrix in column-major order. This means that the a, b, c, and d parameters, for example, line up as the first column in a 4 x 4 matrix, as Figure 7-15 shows. The first column is the x vector, the second column is the y vector, and the third column is the z vector. Figure 7-15 3D matrix parameters Following are some common parameter settings for 3D transforms: ● Identity matrix—matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1) ● Translate matrix—matrix3d(1,0,0,tX,0,1,0,tY,0,0,1,tZ,0,0,0,1) ● Scale matrix—matrix3d(sX,0,0,0,0,sY,0,0,0,0,sZ,0,0,0,0,1) ● RotateX(a) matrix—matrix3d(1,0,0,0,0,cos(a),sin(a),0,0,sin(-a),cos(a),0,0,0,0,1) ● RotateY(a) matrix—matrix3d(cos(a),0,sin(-a),0,0,1,0,0,sin(a),0,cos(a),0,0,0,0,1) Working with Transforms in JavaScript There are a few things to be aware of when using JavaScript to control transforms. Using 2D and 3D Transforms Working with Transforms in JavaScript 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 84The CSS names for transform properties are different than the JavaScript names. When using JavaScript to set a property, delete the hyphens from the property name and capitalize the first letter of the following word. The following snippet shows how to set properties for an element with the ID "myElement" in CSS and JavaScript:

This page contains no images.

X Axis
Y Axis
Z Axis

Back

Front

Right

Left

Bottom

Using 2D and 3D Transforms Example: Animated Rotating Box Under JavaScript Control 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 88

Top


RotateX:
RotateY:

Figure 7-16 3D transforms under JavaScript control Using 2D and 3D Transforms Example: Animated Rotating Box Under JavaScript Control 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 89Use visual effects in combination with mouse and touch events to create interactive web applications that work equally well on the desktop and on iOS-based devices—applications that enable the users to manipulate objects on the screen with the mouse or with their fingers. Using a Click or Tap to Trigger a Transition Effect In this first example, the user can click an element using the mouse or tap an element using a finger to change the element’s size. The change in size is a 2D CSS transform animated using a CSS transition. A finger tap triggers an onclick event in Safari on iOS, so an event handler for onclick events is all you need to handle both tap and click events. First, the example in Listing 8-1 defines an class of element to manipulate and sets the properties needed to animate the transition using CSS. Next, the example defines a simple JavaScript function to change the element’s size using a CSS transform. Finally, the example installs the function as an event handler for onclick events on the element. Figure 8-1 shows the results. Listing 8-1 Simple touch or tap handler Click or tap to grow

Click or tap to grow.

Figure 8-1 Click and tap handler Controlling a 3D Transform with a Click, Touch, or Swipe In the next example, the user can flip a virtual page forward or backward with a click, a tap, or a swipe. Two div elements are styled to look like pages and are positioned back to back, and the example uses a 3D transform to create an animation that looks like the page of a book turning. Adding Interactive Control to Visual Effects Controlling a 3D Transform with a Click, Touch, or Swipe 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 91Any click, tap, or swipe on the page causes the page to turn, so in this case the direction of the swipe doesn’t matter. Both a single tap and a swipe gesture trigger a touchend event when they complete, so the example installs an event listener for the touchend event to handle taps and swipes as well as a listener for the click event. The example uses CSS to define the body element as a 3D container with perspective and to define a page class, with front and back subclasses. To make the page flip animation look like the page of a book turning, the div elements pivot on an edge, instead of around the middle. Consequently, the pages are positioned side by side,so that they lie on top of each other when one isfrontside-up and the other is backside-up, flipped 180 degrees around its edge. JavaScript functions flip the pages back and forth by applying 3D transforms. An onload function installs the page flipping functions as event listeners, with a different flip direction installed for the front and back subclasses. An additional listener function is installed for touchmove events to prevent a swipe from scrolling the browser window, which is the default behavior in Safari on iOS. There is a complication in using the touchend event to detect a tap while at the same time using the click event to detect a mouse click: a tap generates both a touchend event and a click event. To prevent the page flip from being called twice by a tap, an event listener is installed for the touchstart event. If a touchstart event occurs, the user is using a finger, not a mouse, so the listener functions for the click event are removed. Because the click event listeners need to be removed only once, the touchstart event listener removes itself as well. Adding Interactive Control to Visual Effects Controlling a 3D Transform with a Click, Touch, or Swipe 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 92The example uses HTML to create div elements of the page front and page back classes, to hold the page content, and to call the JavaScript function that installsthe event listeners on page load. The complete example is in Listing 8-2 and is illustrated in Figure 8-2. Figure 8-2 Page flip in action Listing 8-2 Page flip on click, tap, or swipe Page turner

Click, tap, or swipe to turn the page.

Back

Front

Using Gestures to Scale and Rotate Elements The final example uses pinch and rotate gestures to scale and rotate an element. Gesture events are high-level eventsthat encapsulate the lower-level touch events—they are instances of the GestureEvent class. Gesture and touch events can occur at the same time. Consequently, you can choose to handle touch events, gesture events, or both. The advantage of gesture events is that the location and angle of the fingers are properties of the events. Gesture events support pinching open and closed to zoom in and zoom out, and pivoting to rotate elements. Adding Interactive Control to Visual Effects Using Gestures to Scale and Rotate Elements 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 95The example in Listing 8-3 first defines the style of the element to manipulate using CSS. The example then declares three JavaScript functions: one function to set the element’s scale and rotation dynamically during a gesture; a second function to preserve the element’s current scale and rotation when the gesture ends; and a third function to install the first two functions as event listeners. Finally, the example uses HTML to create an element, give it content, and call the function that installsthe event listeners on page load. Figure 8-3 illustrates the result. Figure 8-3 Element rotated by a gesture Listing 8-3 Responding to gesture events pinch and rotate
Adding Interactive Control to Visual Effects Using Gestures to Scale and Rotate Elements 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 97

Pinch in to shrink.

Pinch out to grow.

Twirl to rotate.

Adding Interactive Control to Visual Effects Using Gestures to Scale and Rotate Elements 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 98This table describes the changes to Safari CSS Visual Effects Guide . Date Notes 2012-07-23 Documented support for CSS filters. 2012-01-13 Updated artwork and made minor edits. 2011-12-15 Edited and expanded. 2011-11-01 Edited for style and clarity. Updated, expanded, and revised for Safari 5.1 and iOS 5.0. Includes new examples and sample code. 2011-10-12 2011-07-20 Minor typo fix. 2010-11-03 Applied minor edits throughout. 2010-05-26 Made minor edits throughout. Added information on radial gradients and made minor changes to the chapter "Gradients." Added "CSS" to the title. 2010-02-24 2010-01-20 Minor edits. 2009-07-27 Minor edits throughout. 2009-06-08 Minor edits throughout. 2009-03-16 Added CSS gradients, masks, and reflections. New document that describes how to add visual effects to web content that is supported by Safari on the desktop and iOS. 2008-11-19 2012-07-23 | © 2012 Apple Inc. All Rights Reserved. 99 Document Revision HistoryApple Inc. © 2012 Apple Inc. All rights reserved. No part of this publication may be reproduced, stored in a retrievalsystem, or transmitted, in any form or by any means, mechanical, electronic, photocopying, recording, or otherwise, without prior written permission of Apple Inc., with the following exceptions: Any person is hereby authorized to store documentation on a single computer for personal use only and to print copies of documentation for personal use provided that the documentation contains Apple’s copyright notice. No licenses, express or implied, are granted with respect to any of the technology described in this document. Apple retains all intellectual property rights associated with the technology described in this document. This document is intended to assist application developers to develop applications only for Apple-labeled computers. Apple Inc. 1 Infinite Loop Cupertino, CA 95014 408-996-1010 Apple, the Apple logo, Mac, Mac OS, OS X, Safari, and Spotlight are trademarks of Apple Inc., registered in the U.S. and other countries. Java is a registered trademark of Oracle and/or its affiliates. iOS is a trademark or registered trademark of Cisco in the U.S. and other countries and is used under license. Even though Apple has reviewed this document, APPLE MAKES NO WARRANTY OR REPRESENTATION, EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS DOCUMENT, ITS QUALITY, ACCURACY, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.ASARESULT, THISDOCUMENT IS PROVIDED “AS IS,” AND YOU, THE READER, ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND ACCURACY. IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,OR CONSEQUENTIAL DAMAGES RESULTING FROM ANY DEFECT OR INACCURACY IN THIS DOCUMENT, even if advised of the possibility of such damages. THE WARRANTY AND REMEDIES SET FORTH ABOVE ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL OR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer, agent, or employee is authorized to make any modification, extension, or addition to this warranty. Some states do not allow the exclusion or limitation of implied warranties or liability for incidental or consequential damages, so the above limitation or exclusion may not apply to you. This warranty gives you specific legal rights, and you may also have other rights which vary from state to state. USB Device Interface GuideContents Introduction to USB Device Interface Guide 4 Organization of This Document 4 See Also 4 USB Device Overview 6 USB Device Types and Bus Speeds 6 USB Device Architecture and Terminology 7 USB Device Component Descriptors 8 USB Composite Class Devices 8 USB Transfer Types 8 Stalls and Halts 9 Data Synchronization in Non-Isochronous Transfers 10 USB 2.0 and Isochronous Transfers 10 USB Devices on OS X 11 Finding USB Devices and Interfaces 12 USB Family Error Codes 14 Determining Which Interface Version to Use 14 Tasks and Caveats 15 Handling Stalls, Halts, and Data Toggle Resynchronization 15 Using the Low Latency Isochronous Functions 15 Errors Reported by the EHCI Hub 17 Changes in Isochronous Functions to Support USB 2.0 17 USB Device Access in an Intel-Based Macintosh 18 Working With USB Device Interfaces 20 Using USB Device Interfaces 20 Accessing a USB Device 22 Definitions and Global Variables 22 The main Function 23 Working With the Raw Device 27 Working With the Bulk Test Device 34 Working With Interfaces 36 Document Revision History 46 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 2Tables and Listings USB Device Overview 6 Table 1-1 Examples of USB devices 6 Table 1-2 Keys for finding a USB device 12 Table 1-3 Keys for finding a USB interface 13 Working With USB Device Interfaces 20 Listing 2-1 Definitions and global variables 22 Listing 2-2 The main function 24 Listing 2-3 Accessing and programming the raw device 27 Listing 2-4 Releasing the raw device objects 30 Listing 2-5 Configuring a USB device 30 Listing 2-6 Two functions to download firmware to the raw device 32 Listing 2-7 Accessing the bulk test device 34 Listing 2-8 Finding interfaces on the bulk test device 36 Listing 2-9 Two asynchronous I/O completion functions 43 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 3Note: This document was previously titled Working With USB Device Interfaces. The I/O Kit provides a device interface mechanism that allows applications to communicate with and control hardware from outside the kernel. This document focuses on how to use that mechanism to create an application that detects the attachment of a USB device, communicates with it, and detects its detachment. This document does not describe how to develop an in-kernel driver for a USB modem or networking device. If you need to do this, refer to the documentation and sample code listed in “See Also” (page 4). Important: If your application is sandboxed, it must request the com.apple.security.device.usb entitlement in order to access USB devices. Organization of This Document This document contains the following chapters: ● “USB Device Overview” (page 6) provides an overview of USB device architecture and terminology and describes how USB devices are represented in OS X. ● “Working With USB Device Interfaces” (page 20) describes how to use the device interface mechanism to create a command-line tool that accesses a USB device. ● “Document Revision History” (page 46) lists the revisions of this document. See Also The ADC Reference Library contains several documents on device driver development for OS X and numerous sample drivers and applications. ● Accessing Hardware From Applications describes various ways to access devices from outside the kernel, including the device interface mechanism provided by the I/O Kit. For an overview of the I/O Kit terms and concepts used in this document, read the chapter Device Access and the I/O Kit. 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 4 Introduction to USB Device Interface Guide● I/O Kit Framework Reference contains API reference for I/O Kit methods and functions and for specific device families. ● Sample Code > Hardware & Drivers > USB includes both application-level and in-kernel code samples. Of particular relevance to this document is the application-level sample USBPrivateDataSample . ● OS X Man Pages provides access to existing reference documentation for BSD and POSIX functions and tools in a convenient HTML format. ● The usb mailing list provides a forum for discussing technical issues relating to USB devices in OS X. If you need to develop an in-kernel driver for a USB modem or networking device, refer to the following: ● I/O Kit Fundamentals describesthe architecture ofthe I/OKit,the object-oriented framework for developing OS X device drivers. ● ADC members can view the AppleUSBCDCDriver project in the source code for OS X v10.3.7 and later, available at Darwin Releases. To find the source code, select a version of OS X equal to or greater than v10.3.7 and click Source (choose the source for the PPC version, if there's a choice). This displays a new page, which lists the open source projects available for the version of OS X you've chosen. Scroll down to AppleUSBCDCDriver and click it to view the source. Be prepared to supply your ADC member name and password. ● Additional code samples that demonstrate specific in-kernel driver programming techniques are included as part of the OS X Developer Toolsinstallation package in /Developer/Examples/Kernel/IOKit/usb. If you're ready to create a universal binary version of your USB device-access application to run in an Intel-based Macintosh,seeUniversalBinaryProgrammingGuidelines.TheUniversalBinaryProgrammingGuidelines describes the differences between the Intel and PowerPC architectures and provides tips for developing a universal binary. If you are working with a device that complies with the USB mass storage specification but declares its device class to be vendor specific, see Mass Storage Device Driver Programming Guide for information on how to ensure the correct built-in driver loads for the device. Apple provides additional USB information (including the OS X USB Debug Kits) at http://developer.apple.com/hardwaredrivers/usb/index.html. A detailed description of the USB device specification is beyond the scope of this document—for more information, see Universal Serial Bus Specification Revision 2.0 available at http://www.usb.org. Introduction to USB Device Interface Guide See Also 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 5This chapter provides a summary of USB device architecture and describes how USB devices are represented in OS X. It also presents a few specific guidelines for working with USB devices in an application.For details on the USB specification, see http://www.usb.org. USB Device Types and Bus Speeds The USB specification supports a wide selection of devices that range from lower-speed devices such as keyboards, mice, and joysticks to higher-speed devices such as scanners and digital cameras. The specification lists a number of device classes that each define a set of expected device behaviors. Table 1-1 (page 6) lists some examples of USB devices, categorized by class. Table 1-1 Examples of USB devices USB device class USB devices in class Audio class Speakers, microphones Chip Card Interface Device Class Smart cards, chip cards Communication class Speakerphone, modem A device in which all class-specific information is embedded in its interfaces Composite class HID class Keyboards, mice, joysticks, drawing tablets Hub class Hubs provide additional attachment points for USB devices Hard drives, flash memory readers, CD Read/Write drives, digital cameras, and high-end media players Mass storage class Printing class Printers A device that doesn’t fit into any other predefined class or one that doesn’t use the standard protocols for an existing class Vendor specific Digital camcorders, webcams, digital still cameras that support video streaming Video class 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 6 USB Device OverviewVersion 1.1 of the USB specification supports two bus speeds: ● Low speed (1.5 Mbps) ● Full speed (12 Mbps) Version 2.0 of the specification adds another bus speed to this list: ● High speed (480 Mbps) The USB 2.0 specification is fully compatible with low-speed and full-speed USB devices and even supports the use of cables and connectors made to meet earlier versions of the specification. Apple provides USB 2.0 ports on all new Macintosh computers and fully supports the new specification with Enhanced Host Controller Interface (EHCI) controllers and built-in, low-level USB drivers. For the most part, you do not have to change existing applications to support the faster data rate because the speed increase and other enhancements are implemented at such a low level. The exceptions to this are some differences in isochronous transfers. For information on how the USB 2.0 specification affects isochronous transfers, see “USB 2.0 and Isochronous Transfers” (page 10). USB Device Architecture and Terminology The architecture of a generic USB device is multi-layered. A device consists of one or more configurations, each of which describes a possible setting the device can be programmed into. Such settings can include the power characteristics of the configuration (for example, the maximum power consumed by the configuration and whether it is self-powered or not) and whether the configuration supports remote wake-up. Each configuration contains one or more interfacesthat are accessible after the configuration isset. An interface provides the definitions of the functions available within the device and may even contain alternate settings within a single interface. For example, an interface for an audio device may have different settings you can select for different bandwidths. Each interface contains zero or more endpoints. An endpoint is a uniquely identifiable portion of a USB device that is the source or sink of information in a communication flow between the host and the device. Each endpoint has characteristics that describe the communication it supports, such as transfer type (control, isochronous, interrupt, or bulk, described in “USB Transfer Types” (page 8)), maximum packet size, and transfer direction (input or output). Communication with a USB device is accomplished through a pipe, a logical association between an endpoint and software running on the host. Endpoint and pipe are often used synonymously although an endpoint is a component of a USB device and a pipe is a logical abstraction of the communications link between endpoint and host. USB Device Overview USB Device Architecture and Terminology 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 7USB Device Component Descriptors Each layer of a USB device providesinformation about its attributes and resource requirementsin its descriptor, a data structure accessible through device interface functions. By examining the descriptors at each layer, you can determine exactly which endpoint you need to communicate successfully with a particular device. At the top layer is the device descriptor, which has fields associated with information such as the device’s class and subclass, vendor and product numbers, and number of configurations. Each configuration in turn has a configuration descriptor containing fields that describe the number of interfaces it supports and the power characteristics of the device when it is in that configuration, along with other information. Each interface supported by a configuration has its own descriptor with fields for information such as the interface class, subclass, and protocol, and the number of endpoints in that interface. At the bottom layer are the endpoint descriptors that specify attributes such as transfer type and maximum packet size. The USB specification defines a name for each descriptor field, such as the bDeviceClass field in the device descriptor and the bNumInterfaces field in the configuration descriptor, and each field is associated with a value. For a complete listing of all descriptor fields, see the USB specification at www.usb.org. The USB family defines structures that represent the descriptors defined by the USB specification. For the definitions of these structures, see USB in Kernel Framework Reference . USB Composite Class Devices The USB specification defines a composite class device as a device whose device-descriptor fields for device class (bDeviceClass) and device subclass (bDeviceSubClass) both have the value 0. A composite class device appears to the system as a USB device using a single bus address that may present multiple interfaces, each of which represents a separate function. A good example of a composite class device is a multifunction device, such as a device that performs printing, scanning, and faxing. In such a device, each function is represented by a separate interface. In OS X, the I/O Kit loads the AppleUSBComposite device driver for composite class devices that do not already have vendor-specific device drivers to drive them. The AppleUSBComposite driver configures the device and causes drivers to be loaded for each USB interface. Although most multifunction USB devices are composite class devices, not all composite class devices are multifunction devices. The manufacturer of a single-function USB device is at liberty to classify the device as a composite class device as long as the device meets the USB specifications. For more information on how OS X represents USB devices and interfaces, see “USB Devices on OS X” (page 11). USB Transfer Types The USB specification defines four types of pipe transfer: ● Control—intended to support configuration, command, and status communication between the host software and the device. Control transfers support error detection and retry. USB Device Overview USB Device Architecture and Terminology 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 8● Interrupt—used to support small, limited-latency transfers to or from a device such as coordinates from a pointing device or status changes from a modem. Interrupt transfers support error detection and retry. ● Isochronous—used for periodic, continuous communication between the host and the device, usually involving time-relevant information such as audio or video data streams. Isochronous transfers do not support error detection or retry. ● Bulk—intended for non-periodic, large-packet communication with relaxed timing constraints such as between the host software and a printer or scanner. Bulk transfers support error detection and retry. Pipes also have a transfer direction associated with them. A control pipe can support bidirectional communication but all other pipes are strictly uni-directional. Therefore, two-way communication requires two pipes, one for input and one for output. Every USB device is required to implement a default control pipe that provides access to the device’s configuration, status, and control information. This pipe, implemented in the IOUSBDevice nub object (described in “USB Devices on OS X” (page 11)), is used when a driver such as the AppleUSBComposite driver configures the device or when device-specific control and status information is needed. For example, your application would use the default control pipe if it needs to set or choose a configuration for the device. The default control pipe is connected to the default endpoint (endpoint 0). Note that endpoint 0 does not provide an endpoint descriptor and it is never counted in the total number of endpoints in an interface. The interfaces associated with a configuration can contain any combination of the three remaining pipe types (interrupt, isochronous, and bulk), implemented in the IOUSBInterface nub objects (described in “USB Devices on OS X” (page 11)). Your application can query the interface descriptors of a device to select the pipe most suited to its needs. Stalls and Halts Although a stall and a halt are different, they are closely related in their effect on data transmission. Halt is a feature of an endpoint and it can be set by either the host or the device itself in response to an error. A stall is a type of handshake packet an endpoint returns when it is unable to transmit or receive data or when its halt feature is set (the host never sends a stall packet). When an endpoint sends a stall packet, the host can halt the endpoint. Depending on the precise circumstances and on how compliant the device is, the halt feature must be cleared in the host, the endpoint, or both before data transmission can resume. When the halt is cleared the data toggle bit, used to synchronize data transmission, is also reset (see “Data Synchronization in Non-Isochronous Transfers” (page 10) for more information about the data toggle). For information on how to handle these conditions in your application, see “Handling Stalls, Halts, and Data Toggle Resynchronization” (page 15). USB Device Overview USB Device Architecture and Terminology 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 9Data Synchronization in Non-Isochronous Transfers The USB specification defines a simple protocol to provide data synchronization across multiple packets for non-isochronoustransfers(recall that isochronoustransfers do notsupport error recovery or retry). The protocol is implemented by means of a data toggle bit in both the host and the endpoint which is synchronized at the start of a transaction (or when a reset occurs). The precise synchronization mechanism varies with the type of transfer; see the USB specification for details. Both the host and the endpoint begin a transaction with their data toggle bitsset to zero. In general, the entity receiving data toggles its data toggle bit when it is able to accept the data and it receives an error-free data packet with the correct identification. The entity sending the data toggles its data toggle bit when it receives a positive acknowledgement from the receiver. In this way, the data toggle bits stay synchronized until, for example, a packet with an incorrect identification is received. When this happens, the receiver ignores the packet and does not increment its data toggle bit. When the data toggle bits get out of synchronization (for this or any other reason), you will probably notice that alternate transactions are not getting through in your application. The solution to this is to resynchronize the data toggle bits. For information on how to do this, see “Handling Stalls, Halts, and Data Toggle Resynchronization” (page 15). USB 2.0 and Isochronous Transfers The USB 2.0 specification supports the same four transfer types as earlier versions of the specification. In addition to supporting a higher transfer rate, the new specification defines an improved protocol for high-speed transfers and new ways of handling transactions for low-speed and full-speed devices. For details on the protocols and transaction-handling methods, see the specification at http://www.usb.org. For the most part, these enhancements are implemented at the hostsoftware level and do not require changes to your code. For isochronous transfers, however, you should be aware of the following differences: ● Earlier versions of the specification divide bus time into 1-millisecond frames, each of which can carry multiple transactionsto multiple destinations. (A transaction containstwo or more packets: a token packet and one or more data packets, a handshake packet, or both.) The USB 2.0 specification divides the 1-millisecond frame into eight, 125-microsecond microframes, each of which can carry multiple transactions to multiple destinations. ● The maximum amount of data allowed in a transaction is increased to 3 KB. ● Any isochronous endpoints in a device’s default interface must have a maximum packet size of zero. (This means that the default setting for an interface containing isochronous pipes is alternate setting zero and the maximum packet size for that interface’s isochronous endpoints must be zero.) This ensures that the host can configure the device no matter how busy the bus is. For a summary of how these differences affect the OS X USB API, see “Changes in Isochronous Functions to Support USB 2.0” (page 17). USB Device Overview USB Device Architecture and Terminology 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 10USB Devices on OS X When a USB device is plugged in, the OS X USB family abstracts the contents of the device descriptor into an I/O Kit nub object called an IOUSBDevice. This nub object is attached to the IOService plane of the I/O Registry as a child of the driver for the USB controller. The IOUSBDevice nub object is then registered for matching with the I/O Kit. If the device is a composite class device with no vendor-specific driver to match against it, the AppleUSBComposite driver matches against it and starts as its provider. The AppleUSBComposite driver then configures the device by setting the configuration in the device’s list of configuration descriptors with the maximum power usage that can be satisfied by the port to which the device is attached. This allows a device with a low power and a high power configuration to be configured differently depending on whether it’s attached to a bus-powered hub or a self-powered hub. In addition, if the IOUSBDevice nub object has the “Preferred Configuration” property, the AppleUSBComposite driver will always use that value when it attempts to configure the device. The configuration of the device causes the USB family to abstract each interface descriptor in the chosen configuration into an IOUSBInterface nub object. These nub objects are attached to the I/O Registry as children of the original IOUSBDevice nub object and are registered for matching with the I/O Kit. Important: Because a composite class device is configured by the AppleUSBComposite driver, setting the configuration again from your application will result in the destruction of the IOUSBInterface nub objects and the creation of new ones. In general, the only reason to set the configuration of a composite class device that’s matched by the AppleUSBComposite driver is to choose a configuration other than the first one. For non-composite class devices or composite class devices with vendor-specific drivers that match against them, there is no guarantee that any configuration will be set and you may have to perform this task within your application. It's important to be mindful of the difference between a USB device (represented in the I/O Registry by an IOUSBDevice nub object) and its interfaces (each represented by an IOUSBInterface nub object). A multifunction USB device, for example, is represented in the I/O Registry by one IOUSBDevice object and one IOUSBInterface object for each interface. The distinction between interface and device isimportant because it determines which object your application must find in the I/O Registry and which type of device interface to get. For example, if your application needs to communicate with a specific interface in a multifunction USB device, it must find that interface and get an IOUSBInterfaceInterface to communicate with it. An application that needs to communicate with the USB device as a whole, on the other hand, would need to find the device in the I/O Registry and get an IOUSBDeviceInterface to communicate with it. For more information on finding devices and interfaces in USB Device Overview USB Devices on OS X 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 11the I/O Registry, see “Finding USB Devices and Interfaces” (page 12); for more information on how to get the proper device interface to communicate with a device or interface, see “Using USB Device Interfaces” (page 20). Finding USB Devices and Interfaces To find a USB device or interface, use the keys defined in the Universal Serial Bus Common Class Specification, Revision 1.0 (available for download from http://www.usb.org/developers/devclass_docs/usbccs10.pdf) to create a matching dictionary that defines a particular search. If you are unfamiliar with the concept of device matching, see the section “Finding Devices in the I/O Registry” in Accessing Hardware From Applications. The keys defined in the specification are listed in the tables below. Each key consists of a specific combination of elements in a device or interface descriptor. In the tables below, the elements in a key are separated by the ‘+’ character to emphasize the requirement that all a key’s elements must appear together in your matching dictionary. Both tables present the keys in order of specificity: the first key in each table defines the most specific search and the last key defines the broadest search. Before you build a matching dictionary, be sure you know whether your application needs to communicate with a device or a specific interface in a device. It’s especially important to be aware of this distinction when working with multifunction devices. A multifunction device is often a composite class device that defines a separate interface for each function. If, for example, your application needs to communicate with the scanning function of a device that does scanning, faxing, and printing, you need to build a dictionary to match on only the scanning interface (an IOUSBInterface object), not the device as a whole (an IOUSBDevice object). In this situation, you would use the keys defined for interface matching (those shown in Table 1-3 (page 13)), not the keys for device matching. Table 1-2 (page 12) lists the keys you can use to find devices (not interfaces). Each key element is a piece of information contained in the device descriptor for a USB device. Table 1-2 Keys for finding a USB device Key Notes bcdDevice contains the release number of the device idVendor + idProduct + bcdDevice idVendor + idProduct Use this key only if the device’s bDeviceClass is $FF idVendor + bDeviceSubClass + bDeviceProtocol Use this key only if the device’s bDeviceClass is $FF idVendor + bDeviceSubClass USB Device Overview USB Devices on OS X 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 12Key Notes Use this key only if the device’s bDeviceClass is not $FF bDeviceClass + bDeviceSubClass + bDeviceProtocol Use this key only if the device’s bDeviceClass is not $FF bDeviceClass + bDeviceSubClass Table 1-3 (page 13) lists the keys you can use to find interfaces (not devices). Each key element is a piece of information contained in an interface descriptor for a USB device. Table 1-3 Keys for finding a USB interface Key Notes idVendor + idProduct + bcdDevice + bConfigurationValue + bInterfaceNumber idVendor + idProduct + bConfigurationValue + bInterfaceNumber Use this key only if bInterfaceClass is $FF idVendor + bInterfaceSubClass + bInterfaceProtocol Use this key only if bInterfaceSubClass is $FF idVendor + bInterfaceSubClass Use this key only if bInterfaceSubClass is not $FF bInterfaceClass + bInterfaceSubClass + bInterfaceProtocol Use this key only if bInterfaceSubClass is not $FF bInterfaceClass + bInterfaceSubClass For a successful search, you must add the elements of exactly one key to your matching dictionary. If your matching dictionary contains a combination of elements not defined by any key, the search will be unsuccessful. For example, if you create a matching dictionary containing values representing a device’s vendor, product, and protocol, the search will be unsuccessful even if a device with those precise values in its device descriptor is currently represented by an IOUSBDevice nub in the I/O Registry. This is because there is no key in Table 1-2 (page 12) that combines the idVendor, idProduct, and bDeviceProtocol elements. USB Device Overview USB Devices on OS X 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 13USB Family Error Codes As you develop an application to access a USB device or interface, you will probably encounter error codes specific to the OS X USB family. If you are using Xcode, you can search for information about these error codes in the Xcode documentation window. To find error code documentation, select Documentation from the Xcode Help menu. Select Full-Text Search from the pull-down menu associated with the search field (click the magnifying glass icon to reveal the menu). Select Reference Library in the Search Groups pane at the left of the window. Type an error code number in the search field, such as 0xe0004057, and press Return. Select the most relevant entry in the search results to display the document in the lower portion of the window. Use the Find command (press Command-F) to find the error code in this document. Using the example of error code 0xe0004057, you’ll see that this error is returned when the endpoint has not been found. For help with deciphering I/O Kit error codes in general, see Technical Q&A QA1075, “Making sense of I/O Kit error codes.” Determining Which Interface Version to Use As described in “USB Devices on OS X” (page 11), the OS X USB family provides an IOUSBDeviceInterface object you use to communicate with a USB device as a whole and an IOUSBInterfaceInterface object you use to communicate with an interface in a USB device. There are a number of different versions of the USB family, however, some of which provide new versions of these interface objects. (One way to find the version of the USB family installed in your computer is to view the Finder preview information for the IOUSBFamily.kext located in /System/Library/Extensions.) This section describes how to make sure you use the correct interface object and how to view the documentation for the interface objects. The first version of the USB family was introduced in OS X v10.0 and contains the first versions of the interface objects IOUSBDeviceInterface and IOUSBInterfaceInterface. When new versions of the USB family introduce new functions for an interface object, a new version of the interface object is created, which gives access to both the new functions and all functions defined in all previous versions of that interface object. For example, the IOUSBDeviceInterface197 object provides two new functions you can use with version 1.9.7 of the USB family (available in OS X v10.2.3 and later), in addition to all functions available in the previous device interface objects IOUSBDeviceInterface187, IOUSBDeviceInterface182, and IOUSBDeviceInterface. As you develop an application that accesses a USB device or interface, you should use the latest version of the interface object that is available in the earliest version of OS X that you want to support. For example, if your application must run in OS X v10.0, you must use the IOUSBDeviceInterface and IOUSBInterfaceInterface objects. If, however, you develop an application to run in OS X v10.4 and later, you use the IOUSBDeviceInterface197 object to access the device as a whole and the USB Device Overview USB Devices on OS X 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 14IOUSBInterfaceInterface220 object to access an interface in it. This is because IOUSBDeviceInterface197 is available inOS X version 10.2.3 and later and IOUSBInterfaceInterface220 is available in OS X v10.4 and later. Note: When you view the documentation for these interface objects, notice that each version is documented separately. For example, the documentation for IOUSBDeviceInterface197 contains information about the two new functions introduced in this version, but does not repeat the documentation for the functions introduced in IOUSBDeviceInterface187, IOUSBDeviceInterface182, and IOUSBDeviceInterface. Tasks and Caveats This section presents some specific tasks your application might need to perform, along with some caveats related to USB 2.0 support of which you should be aware. Handling Stalls, Halts, and Data Toggle Resynchronization As described in “Stalls and Halts ” (page 9), stalls and halts are closely related in their effect on data transmission. To simplify the API, the USB family uses the pipe stall terminology in the names of the functions that handle these conditions: ● ClearPipeStall ● ClearPipeStallBothEnds The ClearPipeStall function operates exclusively on the host controller side, clearing the halt feature and resetting the data toggle bit to zero. If the endpoint’s halt feature and data toggle bit must be reset as well, your application must do so explicitly, using one of the ControlRequest functions to send the appropriate device request. See the documentation for the USB.h header file in I/O Kit Framework Reference for more information about standard device requests. In OS X version 10.2 and later, you can use the ClearPipeStallBothEnds function which, as its name suggests, clears the halt and resets the data toggle bit on both sides at the same time. Using the Low Latency Isochronous Functions In OS X, the time between when an isochronous transaction completes on the USB bus and when you receive your callback can stretch to tens of milliseconds. This is because the callback happens on the USB family work loop, which runs at a lower priority than some other threads in the system. In most cases, you can work around USB Device Overview Tasks and Caveats 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 15this delay by queuing read and write requests so that the next transaction is scheduled and ready to start before you receive the callback from the current transaction. In fact, this scheme is a good way to achieve higher performance whether or not low latency is a requirement of your application. In a few cases, however, queuing isochronous transactions to keep the pipe busy is not enough to prevent a latency problem that a user might notice. Consider an application that performs audio processing on some USB input (from a musical instrument, for example) before sending the processed data out to USB speakers. In this scenario, a user hears both the raw, unprocessed output of the instrument and the processed output of the speakers. Of course, some small delay between the time the instrument creates the raw sound waves and the time the speaker emits the processed sound waves is unavoidable. If this delay is greater than about 8 milliseconds, however, the user will notice. In OS X version 10.2.3 (version 1.9.2 of the USB family) the USB family solves this problem by taking advantage of the predictability of isochronous data transfers. By definition, isochronous mode guarantees the delivery of some amount of data every frame or microframe. In earlier versions of OS X, however, it was not possible to find out the exact amount of data that was transferred by a given time. This meant that an application could not begin processing the data until it received the callback associated with the transaction, telling it the transfer status and the actual amount of data that was transferred. Version 1.9.2 of the USB family introduced the LowLatencyReadIsochPipeAsync and LowLatencyWriteIsochPipeAsync functions. These functions update the frame list information (including the transferstatus and the number of bytes actually transferred) at primary interrupt time. Using these functions, an application can request that the frame list information be updated as frequently as every millisecond. This means an application can retrieve and begin processing the number of bytes actually transferred once a millisecond, without waiting for the entire transaction to complete. Important: Because these functions cause processing at primary interrupt time, it is essential you use them only if it is absolutely necessary. Overuse of these functions can cause degradation of system performance. To support the low latency isochronous read and write functions, the USB family also introduced functions to create and destroy the buffers that hold the frame list information and the data. Although you can choose to create a single data buffer and a single frame list buffer or multiple buffers of each type, you must use the LowLatencyCreateBuffer function to create them. Similarly, youmust use the LowLatencyDestroyBuffer function to destroy the buffers after you are finished with them. This restricts all necessary communication with kernel entities to the USB family. For reference documentation on the low latency isochronous functions, see the IOUSBLib.h documentation in I/O Kit Framework Reference . USB Device Overview Tasks and Caveats 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 16Errors Reported by the EHCI Hub The EHCI hub that supports high-speed devices (as well as low-speed and full-speed devices) provides coarser-grained error reporting than the OHCI hub does. For example, with an OHCI hub, you might receive an “endpoint timed out” error if you unplug the device while it is active. If you perform the same action with an EHCI hub, you might receive a “pipe stalled” error instead. The Apple EHCI hub driver cannot get more detailed error information from the hub, so it alternates between reporting “device not responding” and “pipe stalled” regardless of the actual error reported by the device. To avoid problems with your code, be sure your application does not rely on other, more specific errors to make important decisions. Changes in Isochronous Functions to Support USB 2.0 Recall that the USB 2.0 specification divides the 1-millisecond frame into eight, 125-microsecond microframes. The USB family handles this by reinterpreting some function parameters (where appropriate) and adding a couple of new functions. This section summarizes these changes; for reference documentation, see documentation for IOUSBLib.h in I/O Kit Framework Reference . The functions you use to read from and write to isochronous endpoints are ReadIsochPipeAsync and WriteIsochPipeAsync. Both functions include the following two parameters: ● numFrames—The number of frames for which to transfer data ● frameList—A pointer to an array of structures that describe the frames If you need to handle high-speed isochronous transfers, you can think of these parameters as referring to “transfer opportunities” instead of frames. In other words, numFrames can refer to a number of frames for full-speed devices or to a number of microframes for high-speed devices. Similarly, frameList specifies the list of transfers you want to occur, whether they are in terms of frames or microframes. Note: The ReadIsochPipeAsync and WriteIsochPipeAsync functions also have the frameStart parameter in common, but it does not get reinterpreted. Thisis because all isochronoustransactions, including high-speed isochronoustransactions,start on a frame boundary, not amicroframe boundary. To help you determine whether a device isfunctioning in full-speed or high-speed mode, the USB family added the GetFrameListTime function, which returns the number of microseconds in a frame. By examining the result (kUSBFullSpeedMicrosecondsInFrame or kUSBHighSpeedMicrosecondsInFrame) you can tell in which mode the device is operating. USB Device Overview Tasks and Caveats 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 17The USB family also added the GetBusMicroFrameNumber function which is similar to the GetBusFrameNumber function, except that it returns both the current frame and microframe number and includes the time at which that information was retrieved. To handle the new specification’s requirement that isochronous endpoints in a device’s default interface have a maximum packetsize of zero, the USB family added functionsthat allow you to balance bandwidth allocations among isochronous endpoints. A typical scenario is this: 1. Call GetBandwidthAvailable (available inOS X version 10.2 and later)to determine howmuch bandwidth is currently available for allocation to isochronous endpoints. 2. Call GetEndpointProperties (available in OS X version 10.2 and later) to examine the alternate settings of an interface and find one that uses an appropriate amount of bandwidth. 3. Call SetAlternateInterface (available in OS X version 10.0 and later) to create the desired interface and allocate the pipe objects. 4. Call GetPipeProperties (available in OS X version 10.0 and later) on the chosen isochronous endpoint. Thisis a very importantstep because SetAlternateInterface willsucceed, even if there is not enough bandwidth for the endpoints. Also, another device might have claimed the bandwidth that was available at the time the GetBandwidthAvailable function returned. If this happens, the maximum packet size for your chosen endpoint (contained in the maxPacketSize field) is now zero, which means that the bandwidth is no longer available. In addition, in OS X version 10.2, the USB family added the SetPipePolicy function, which allows you to relinquish bandwidth that might have been specified in an alternate setting. USB Device Access in an Intel-Based Macintosh This section provides an overview of some of the issues related to developing a universal binary version of an application that accesses a USB device. Before you read this section, be sure to read Universal Binary Programming Guidelines. That document covers architectural differences and byte-ordering formats and provides comprehensive guidelines for code modification and building universal binaries. The guidelines in that document apply to all types of applications, including those that access hardware. Before you build your application as a universal binary, make sure that: ● You port your project to GCC 4 (Xcode uses GCC 4 to target Intel-based Macintosh computers) ● You install the OS X v10.4 universal SDK ● You develop your project in Xcode 2.1 or later USB Device Overview USB Device Access in an Intel-Based Macintosh 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 18The USB bus is a little-endian bus. Structured data appears on the bus in the little-endian format regardless of the native endian format of the computer an application isrunning in. If you've developed a USB device-access application to run in a PowerPC-based Macintosh, you probably perform some byte swapping on data you read from the USB bus because the PowerPC processor uses the big-endian format. For example, the USB configuration descriptor structure contains a two-byte field that holds the descriptor length. If your PowerPC application reads this structure from the USB bus (instead of receiving it from a USB device interface function), you need to swap the value from the USB bus format (little endian) to the PowerPC format (big endian). The USB family provides several swapping macros that swap from USB to host and from host to USB (for more information on these macros, see USB.h). The Kernel framework also provides byte-swapping macros and functions you can use in high-level applications (see the OSByteOrder.h header file in libkern). If you use these macros in your application, you shouldn't have any trouble developing a universal binary version of your application. This is because these macros determine at compile time if a swap is necessary. If, however, your application uses hard-coded swaps from little endian to big endian, your application will not run correctly in an Intel-based Macintosh. As you develop a universal binary version of your application, therefore, be sure to use the USB family swapping macros or the macros in libkern/OSByteOrder.h for all byte swapping. Although you may need to perform byte swapping on values your application reads from the USB bus, you do not need to perform any byte swapping on values you pass in arguments to functions in the USB family API. You should pass argument values in the computer's host format. Likewise, any values you receive from the USB family functions will be in the computer's host format. USB Device Overview USB Device Access in an Intel-Based Macintosh 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 19This chapter describes how to develop a user-space tool that finds and communicates with an attached USB device and one of its interfaces. Important: The sample code featured in this document isintended to illustrate how to access a USB device from an application. It is not intended to provide guidance on error handling and other features required for production-quality code. Using USB Device Interfaces Applications running in OS X get access to USB devices by using I/O Kit functions to acquire a device interface, a type of plug-in that specifies functions the application can call to communicate with the device. The USB family provides two types of device interface: ● IOUSBDeviceInterface for communicating with the device itself ● IOUSBInterfaceInterface for communicating with an interface in the device Both device interfaces are defined in /System/Library/Frameworks/IOKit.framework/Headers/usb/IOUSBLib.h. Communicating with the device itself is usually only necessary when you need to set or change its configuration. For example, vendor-specific devices are often not configured because there are no default drivers that set a particular configuration. In this case, your application must use the device interface for the device to set the configuration it needs so the interfaces become available. Important: If your application is sandboxed, it must request the com.apple.security.device.usb entitlement in order to access USB devices. The process of finding and communicating with a USB device is divided into two sets of steps. The first set outlines how to find a USB device, acquire a device interface of type IOUSBDeviceInterface for it, and set or change its configuration. The second set describes how to find an interface in a device, acquire a device interface of type IOUSBInterfaceInterface for it, and use it to communicate with that interface. If you need to communicate with an unconfigured device or if you need to change a device’s configuration, you follow both sets of steps. If you need to communicate with a device that is already configured to your 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 20 Working With USB Device Interfacesspecification, you follow only the second set of steps. The sample code in “Accessing a USB Device” (page 22) follows both sets of steps and extends them to include setting up notifications it can receive when devices are dynamically added or removed. Follow this first set of steps only to set or change the configuration of a device. If the device you’re interested in is already configured for your needs, skip these steps and follow the second set of steps. 1. Find the IOUSBDevice object that represents the device in the I/O Registry. This includes setting up a matching dictionary with a key from the USB Common Class Specification (see “Finding USB Devices and Interfaces” (page 12)). The sample code usesthe key elements kUSBVendorName and kUSBProductName to find a particular USB device (this is the second key listed in Table 1-2 (page 12)). 2. Create a device interface of type IOUSBDeviceInterface for the device. This device interface provides functionsthat perform taskssuch assetting or changing the configuration of the device, getting information about the device, and resetting the device. 3. Examine the device’s configurations with GetConfigurationDescriptorPtr, choose the appropriate one, and call SetConfiguration to set the device’s configuration and instantiate the IOUSBInterface objects for that configuration. Follow thissecond set ofstepsto find and choose an interface, acquire a device interface for it, and communicate with the device. 1. Create an interface iterator to iterate over the available interfaces. 2. Create a device interface for each interface so you can examine its properties and select the appropriate one. To do this, you create a device interface of type IOUSBInterfaceInterface. This device interface providesfunctionsthat perform taskssuch as getting information about the interface,setting the interface’s alternate setting, and accessing its pipes. 3. Use the USBInterfaceOpen function to open the selected interface. This will cause the pipes associated with the interface to be instantiated so you can examine the properties of each and select the appropriate one. 4. Communicate with the device through the selected pipe. You can write to and read from the pipe synchronously or asynchronously—the sample code in “Accessing a USB Device” (page 22) shows how to do both. Working With USB Device Interfaces Using USB Device Interfaces 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 21Accessing a USB Device This section provides snippets of sample code that show how to access a Cypress EZ-USB chip with an 8051 microcontroller core. The sample code followsthe firstset ofstepsin section “Using USB Device Interfaces” (page 20) to find the Cypress EZ-USB chip in its default, unprogrammed state (also referred to as the “raw device”). It then configures the device and downloads firmware provided by Cypress to program the chip to behave as a device that echoes all information it receives on its bulk out pipe to its bulk in pipe. Once the chip has been programmed, the device nub representing the default, unprogrammed device is detached from the I/O Registry and a new device nub, representing the programmed chip, is attached. To communicate with the programmed chip (also referred to as the “bulk test device”), the sample code must perform the first set of steps again to find the device, create a device interface for it, and configure it. Then it performs the second set of steps to find an interface, create a device interface for it, and test the device. The sample code also shows how to set up notifications for the dynamic addition and removal of a device. Important: If your application is sandboxed, it must request the com.apple.security.device.usb entitlement in order to access USB devices. Definitions and Global Variables The code in the USB Notification Example uses the definitions and global variables shown in Listing 2-1 (page 22). The definition of USE_ASYNC_IO allows you to choose to use either synchronous or asynchronous calls to read from and write to the chip by commenting out the line or leaving it in, respectively. The definition of kTestMessage sets up a simple message to write to the device. The remaining definitions are specific to the Cypress EZ-USB chip. Listing 2-1 Definitions and global variables #define USE_ASYNC_IO //Comment this line out if you want to use //synchronous calls for reads and writes #define kTestMessage "Bulk I/O Test" #define k8051_USBCS 0x7f92 #define kOurVendorID 1351 //Vendor ID of the USB device #define kOurProductID 8193 //Product ID of device BEFORE it //is programmed (raw device) #define kOurProductIDBulkTest 4098 //Product ID of device AFTER it is //programmed (bulk test device) //Global variables Working With USB Device Interfaces Accessing a USB Device 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 22static IONotificationPortRef gNotifyPort; static io_iterator_t gRawAddedIter; static io_iterator_t gRawRemovedIter; static io_iterator_t gBulkTestAddedIter; static io_iterator_t gBulkTestRemovedIter; static char gBuffer[64]; The main Function The main function in the USB Notification Example project (contained in the file main.c) accomplishes the following tasks. ● It establishes communication with the I/O Kit and sets up a matching dictionary to find the Cypress EZ-USB chip. ● It sets up an asynchronous notification to be called when an unprogrammed (raw) device is first attached to the I/O Registry and another to be called when the device is removed. ● It modifies the matching dictionary to find the programmed (bulk test) device. ● It sets up additional notifications to be called when the bulk test device is first attached or removed. ● It starts the run loop so the notifications that have been set up will be received. The main function uses I/O Kit functions to set up and modify a matching dictionary and set up notifications, and Core Foundation functions to set up the run loop for receiving the notifications. It calls the following functions to access both the raw device and the bulk test device. ● RawDeviceAdded, shown in Listing 2-3 (page 27), iterates over the set of matching devices and creates a device interface for each one. It calls ConfigureDevice (shown in Listing 2-5 (page 30)) to set the device’s configuration, and then DownloadToDevice (shown in Listing 2-6 (page 32)) to download the firmware to program it. ● RawDeviceRemoved,shown in Listing 2-4 (page 30), iterates over the set of matching devices and releases each one in turn. ● BulkTestDeviceAdded, shown in Listing 2-7 (page 34), iterates over the new set of matching devices, creates a device interface for each one, and calls ConfigureDevice (shown in Listing 2-5 (page 30)) to set the device’s configuration. It then calls FindInterfaces (shown in Listing 2-8 (page 36)) to get access to the interfaces on the device. ● BulkTestDeviceRemoved iterates over the new set of matching devices and releases each one in turn. This function is not shown in this chapter; see RawDeviceRemoved (Listing 2-4 (page 30)) for a nearly identical function. Working With USB Device Interfaces Accessing a USB Device 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 23Listing 2-2 The main function int main (int argc, const char *argv[]) { mach_port_t masterPort; CFMutableDictionaryRef matchingDict; CFRunLoopSourceRef runLoopSource; kern_return_t kr; SInt32 usbVendor = kOurVendorID; SInt32 usbProduct = kOurProductID; // Get command line arguments, if any if (argc > 1) usbVendor = atoi(argv[1]); if (argc > 2) usbProduct = atoi(argv[2]); //Create a master port for communication with the I/O Kit kr = IOMasterPort(MACH_PORT_NULL, &masterPort); if (kr || !masterPort) { printf("ERR: Couldn’t create a master I/O Kit port(%08x)\n", kr); return -1; } //Set up matching dictionary for class IOUSBDevice and its subclasses matchingDict = IOServiceMatching(kIOUSBDeviceClassName); if (!matchingDict) { printf("Couldn’t create a USB matching dictionary\n"); mach_port_deallocate(mach_task_self(), masterPort); return -1; } //Add the vendor and product IDs to the matching dictionary. //This is the second key in the table of device-matching keys of the //USB Common Class Specification Working With USB Device Interfaces Accessing a USB Device 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 24CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorName), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbVendor)); CFDictionarySetValue(matchingDict, CFSTR(kUSBProductName), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbProduct)); //To set up asynchronous notifications, create a notification port and //add its run loop event source to the program’s run loop gNotifyPort = IONotificationPortCreate(masterPort); runLoopSource = IONotificationPortGetRunLoopSource(gNotifyPort); CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode); //Retain additional dictionary references because each call to //IOServiceAddMatchingNotification consumes one reference matchingDict = (CFMutableDictionaryRef) CFRetain(matchingDict); matchingDict = (CFMutableDictionaryRef) CFRetain(matchingDict); matchingDict = (CFMutableDictionaryRef) CFRetain(matchingDict); //Now set up two notifications: one to be called when a raw device //is first matched by the I/O Kit and another to be called when the //device is terminated //Notification of first match: kr = IOServiceAddMatchingNotification(gNotifyPort, kIOFirstMatchNotification, matchingDict, RawDeviceAdded, NULL, &gRawAddedIter); //Iterate over set of matching devices to access already-present devices //and to arm the notification RawDeviceAdded(NULL, gRawAddedIter); //Notification of termination: kr = IOServiceAddMatchingNotification(gNotifyPort, kIOTerminatedNotification, matchingDict, RawDeviceRemoved, NULL, &gRawRemovedIter); Working With USB Device Interfaces Accessing a USB Device 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 25//Iterate over set of matching devices to release each one and to //arm the notification RawDeviceRemoved(NULL, gRawRemovedIter); //Now change the USB product ID in the matching dictionary to match //the one the device will have after the firmware has been downloaded usbProduct = kOurProductIDBulkTest; CFDictionarySetValue(matchingDict, CFSTR(kUSBProductName), CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbProduct)); //Now set up two notifications: one to be called when a bulk test device //is first matched by the I/O Kit and another to be called when the //device is terminated. //Notification of first match kr = IOServiceAddMatchingNotification(gNotifyPort, kIOFirstMatchNotification, matchingDict, BulkTestDeviceAdded, NULL, &gBulkTestAddedIter); //Iterate over set of matching devices to access already-present devices //and to arm the notification BulkTestDeviceAdded(NULL, gBulkTestAddedIter); //Notification of termination kr = IOServiceAddMatchingNotification(gNotifyPort, kIOTerminatedNotification, matchingDict, BulkTestDeviceRemoved, NULL, &gBulkTestRemovedIter); //Iterate over set of matching devices to release each one and to //arm the notification. NOTE: this function is not shown in this document. BulkTestDeviceRemoved(NULL, gBulkTestRemovedIter); //Finished with master port mach_port_deallocate(mach_task_self(), masterPort); masterPort = 0; Working With USB Device Interfaces Accessing a USB Device 2012-01-09 | © 2002, 2012 Apple Inc. All Rights Reserved. 26//Start the run loop so notifications will be received